diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b5eff7910a6..0458dce6e0a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -20,6 +20,7 @@ /appengine/flexible/django_cloudsql/**/* @glasnt @GoogleCloudPlatform/aap-dpes @GoogleCloudPlatform/python-samples-reviewers /appengine/standard_python3/spanner/* @GoogleCloudPlatform/api-spanner-python @GoogleCloudPlatform/python-samples-reviewers /auth/**/* @arithmetic1728 @GoogleCloudPlatform/python-samples-reviewers +/automl/**/* @GoogleCloudPlatform/ml-apis @GoogleCloudPlatform/python-samples-reviewers /batch/**/* @m-strzelczyk @GoogleCloudPlatform/dee-infra @GoogleCloudPlatform/python-samples-reviewers /bigquery/**/* @chalmerlowe @GoogleCloudPlatform/python-samples-reviewers /bigquery/remote_function/**/* @autoerr @GoogleCloudPlatform/python-samples-reviewers diff --git a/.github/blunderbuss.yml b/.github/blunderbuss.yml index a7c8b85bf37..1689daa9992 100644 --- a/.github/blunderbuss.yml +++ b/.github/blunderbuss.yml @@ -147,6 +147,10 @@ assign_issues_by: - 'api: vision' to: - GoogleCloudPlatform/python-samples-reviewers +- labels: + - 'api: vision' + to: + - GoogleCloudPlatform/ml-apis assign_prs_by: - labels: diff --git a/.github/header-checker-lint.yml b/.github/header-checker-lint.yml index 30c6c690f9d..9fba9f2ee47 100644 --- a/.github/header-checker-lint.yml +++ b/.github/header-checker-lint.yml @@ -19,7 +19,6 @@ ignoreFiles: - "texttospeech/snippets/resources/example.txt" - "texttospeech/snippets/resources/hello.txt" - ignoreLicenseYear: true sourceFileExtensions: diff --git a/automl/AUTHORING_GUIDE.md b/automl/AUTHORING_GUIDE.md new file mode 100644 index 00000000000..8249522ffc2 --- /dev/null +++ b/automl/AUTHORING_GUIDE.md @@ -0,0 +1 @@ +See https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/AUTHORING_GUIDE.md \ No newline at end of file diff --git a/automl/CONTRIBUTING.md b/automl/CONTRIBUTING.md new file mode 100644 index 00000000000..f5fe2e6baf1 --- /dev/null +++ b/automl/CONTRIBUTING.md @@ -0,0 +1 @@ +See https://github.com/GoogleCloudPlatform/python-docs-samples/blob/main/CONTRIBUTING.md \ No newline at end of file diff --git a/automl/beta/batch_predict.py b/automl/beta/batch_predict.py new file mode 100644 index 00000000000..65315b4010b --- /dev/null +++ b/automl/beta/batch_predict.py @@ -0,0 +1,59 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# [START automl_batch_predict_beta] +from google.cloud import automl_v1beta1 as automl + + +def batch_predict( + project_id="YOUR_PROJECT_ID", + model_id="YOUR_MODEL_ID", + input_uri="gs://YOUR_BUCKET_ID/path/to/your/input/csv_or_jsonl", + output_uri="gs://YOUR_BUCKET_ID/path/to/save/results/", +): + """Batch predict""" + prediction_client = automl.PredictionServiceClient() + + # Get the full path of the model. + model_full_id = automl.AutoMlClient.model_path( + project_id, "us-central1", model_id + ) + + gcs_source = automl.GcsSource(input_uris=[input_uri]) + + input_config = automl.BatchPredictInputConfig(gcs_source=gcs_source) + gcs_destination = automl.GcsDestination(output_uri_prefix=output_uri) + output_config = automl.BatchPredictOutputConfig( + gcs_destination=gcs_destination + ) + params = {} + + request = automl.BatchPredictRequest( + name=model_full_id, + input_config=input_config, + output_config=output_config, + params=params + ) + response = prediction_client.batch_predict( + request=request + ) + + print("Waiting for operation to complete...") + print( + "Batch Prediction results saved to Cloud Storage bucket. {}".format( + response.result() + ) + ) +# [END automl_batch_predict_beta] diff --git a/automl/beta/batch_predict_test.py b/automl/beta/batch_predict_test.py new file mode 100644 index 00000000000..2869873a919 --- /dev/null +++ b/automl/beta/batch_predict_test.py @@ -0,0 +1,47 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific ladnguage governing permissions and +# limitations under the License. + +import datetime +import os + +import batch_predict + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +BUCKET_ID = "{}-lcm".format(PROJECT_ID) +MODEL_ID = "TEN0000000000000000000" +PREFIX = "TEST_EXPORT_OUTPUT_" + datetime.datetime.now().strftime( + "%Y%m%d%H%M%S" +) + + +def test_batch_predict(capsys): + # As batch prediction can take a long time. Try to batch predict on a model + # and confirm that the model was not found, but other elements of the + # request were valid. + try: + input_uri = "gs://{}/entity-extraction/input.jsonl".format(BUCKET_ID) + output_uri = "gs://{}/{}/".format(BUCKET_ID, PREFIX) + batch_predict.batch_predict( + PROJECT_ID, MODEL_ID, input_uri, output_uri + ) + out, _ = capsys.readouterr() + assert ( + "does not exist" + in out + ) + except Exception as e: + assert ( + "does not exist" + in e.message + ) diff --git a/automl/beta/cancel_operation.py b/automl/beta/cancel_operation.py new file mode 100644 index 00000000000..5fa3e3c2f89 --- /dev/null +++ b/automl/beta/cancel_operation.py @@ -0,0 +1,62 @@ +# -*- coding: utf-8 -*- +# +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# [START automl_cancel_operation] + +from google.cloud import automl_v1beta1 + + +def sample_cancel_operation(project, operation_id): + """ + Cancel Long-Running Operation + + Args: + project Required. Your Google Cloud Project ID. + operation_id Required. The ID of the Operation. + """ + + client = automl_v1beta1.AutoMlClient() + + operations_client = client._transport.operations_client + + # project = '[Google Cloud Project ID]' + # operation_id = '[Operation ID]' + name = "projects/{}/locations/us-central1/operations/{}".format( + project, operation_id + ) + + operations_client.cancel_operation(name) + + print(u"Cancelled operation: {}".format(name)) + + +# [END automl_cancel_operation] + + +def main(): + import argparse + + parser = argparse.ArgumentParser() + parser.add_argument("--project", type=str, default="[Google Cloud Project ID]") + parser.add_argument("--operation_id", type=str, default="[Operation ID]") + args = parser.parse_args() + + sample_cancel_operation(args.project, args.operation_id) + + +if __name__ == "__main__": + main() diff --git a/automl/beta/delete_dataset.py b/automl/beta/delete_dataset.py new file mode 100644 index 00000000000..341e2413584 --- /dev/null +++ b/automl/beta/delete_dataset.py @@ -0,0 +1,30 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# [START automl_delete_dataset_beta] +from google.cloud import automl_v1beta1 as automl + + +def delete_dataset(project_id="YOUR_PROJECT_ID", dataset_id="YOUR_DATASET_ID"): + """Delete a dataset.""" + client = automl.AutoMlClient() + # Get the full path of the dataset + dataset_full_id = client.dataset_path( + project_id, "us-central1", dataset_id + ) + response = client.delete_dataset(name=dataset_full_id) + + print("Dataset deleted. {}".format(response.result())) +# [END automl_delete_dataset_beta] diff --git a/automl/beta/delete_dataset_test.py b/automl/beta/delete_dataset_test.py new file mode 100644 index 00000000000..cf3cdff5669 --- /dev/null +++ b/automl/beta/delete_dataset_test.py @@ -0,0 +1,46 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import uuid + +from google.cloud import automl_v1beta1 as automl +import pytest + +import delete_dataset + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +BUCKET_ID = "{}-lcm".format(PROJECT_ID) + + +@pytest.fixture(scope="function") +def dataset_id(): + client = automl.AutoMlClient() + project_location = f"projects/{PROJECT_ID}/locations/us-central1" + display_name = "test_{}".format(uuid.uuid4()).replace("-", "")[:32] + metadata = automl.VideoClassificationDatasetMetadata() + dataset = automl.Dataset( + display_name=display_name, video_classification_dataset_metadata=metadata + ) + response = client.create_dataset(parent=project_location, dataset=dataset) + dataset_id = response.name.split("/")[-1] + + yield dataset_id + + +def test_delete_dataset(capsys, dataset_id): + # delete dataset + delete_dataset.delete_dataset(PROJECT_ID, dataset_id) + out, _ = capsys.readouterr() + assert "Dataset deleted." in out diff --git a/automl/beta/delete_model.py b/automl/beta/delete_model.py new file mode 100644 index 00000000000..85ad913c3e4 --- /dev/null +++ b/automl/beta/delete_model.py @@ -0,0 +1,31 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def delete_model(project_id, model_id): + """Delete a model.""" + # [START automl_delete_model_beta] + from google.cloud import automl_v1beta1 as automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + + client = automl.AutoMlClient() + # Get the full path of the model. + model_full_id = client.model_path(project_id, "us-central1", model_id) + response = client.delete_model(name=model_full_id) + + print("Model deleted. {}".format(response.result())) + # [END automl_delete_model_beta] diff --git a/automl/beta/delete_model_test.py b/automl/beta/delete_model_test.py new file mode 100644 index 00000000000..2d1fc2da032 --- /dev/null +++ b/automl/beta/delete_model_test.py @@ -0,0 +1,31 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import delete_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +def test_delete_model(capsys): + # As model creation can take many hours, instead try to delete a + # nonexistent model and confirm that the model was not found, but other + # elements of the request were valid. + try: + delete_model.delete_model(PROJECT_ID, "VCN0000000000000000000") + out, _ = capsys.readouterr() + assert "The model does not exist" in out + except Exception as e: + assert "The model does not exist" in e.message diff --git a/automl/beta/get_model.py b/automl/beta/get_model.py new file mode 100644 index 00000000000..9e8dcb9cea7 --- /dev/null +++ b/automl/beta/get_model.py @@ -0,0 +1,42 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def get_model(project_id, model_id): + """Get a model.""" + # [START automl_get_model_beta] + from google.cloud import automl_v1beta1 as automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + + client = automl.AutoMlClient() + # Get the full path of the model. + model_full_id = client.model_path(project_id, "us-central1", model_id) + model = client.get_model(name=model_full_id) + + # Retrieve deployment state. + if model.deployment_state == automl.Model.DeploymentState.DEPLOYED: + deployment_state = "deployed" + else: + deployment_state = "undeployed" + + # Display the model information. + print("Model name: {}".format(model.name)) + print("Model id: {}".format(model.name.split("/")[-1])) + print("Model display name: {}".format(model.display_name)) + print("Model create time: {}".format(model.create_time)) + print("Model deployment state: {}".format(deployment_state)) + # [END automl_get_model_beta] diff --git a/automl/beta/get_model_evaluation.py b/automl/beta/get_model_evaluation.py new file mode 100644 index 00000000000..07ad373842f --- /dev/null +++ b/automl/beta/get_model_evaluation.py @@ -0,0 +1,57 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def get_model_evaluation(project_id, model_id, model_evaluation_id): + """Get model evaluation.""" + # [START automl_video_classification_get_model_evaluation_beta] + # [START automl_video_object_tracking_get_model_evaluation_beta] + from google.cloud import automl_v1beta1 as automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + # model_evaluation_id = "YOUR_MODEL_EVALUATION_ID" + + client = automl.AutoMlClient() + # Get the full path of the model evaluation. + model_path = client.model_path(project_id, "us-central1", model_id) + model_evaluation_full_id = f"{model_path}/modelEvaluations/{model_evaluation_id}" + + # Get complete detail of the model evaluation. + response = client.get_model_evaluation(name=model_evaluation_full_id) + + print("Model evaluation name: {}".format(response.name)) + print("Model annotation spec id: {}".format(response.annotation_spec_id)) + print("Create Time: {}".format(response.create_time)) + print( + "Evaluation example count: {}".format(response.evaluated_example_count) + ) + + # [END automl_video_object_tracking_get_model_evaluation_beta] + + print( + "Classification model evaluation metrics: {}".format( + response.classification_evaluation_metrics + ) + ) + # [END automl_video_classification_get_model_evaluation_beta] + + # [START automl_video_object_tracking_get_model_evaluation_beta] + print( + "Video object tracking model evaluation metrics: {}".format( + response.video_object_tracking_evaluation_metrics + ) + ) + # [END automl_video_object_tracking_get_model_evaluation_beta] diff --git a/automl/beta/get_model_evaluation_test.py b/automl/beta/get_model_evaluation_test.py new file mode 100644 index 00000000000..bdf75e15aa3 --- /dev/null +++ b/automl/beta/get_model_evaluation_test.py @@ -0,0 +1,47 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud import automl_v1beta1 as automl +import pytest + +import get_model_evaluation + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["ENTITY_EXTRACTION_MODEL_ID"] + + +@pytest.fixture(scope="function") +def model_evaluation_id(): + client = automl.AutoMlClient() + model_full_id = client.model_path(PROJECT_ID, "us-central1", MODEL_ID) + request = automl.ListModelEvaluationsRequest( + parent=model_full_id, + filter="" + ) + evaluations = client.list_model_evaluations(request=request) + evaluation = next(iter(evaluations)) + model_evaluation_id = evaluation.name.split( + "{}/modelEvaluations/".format(MODEL_ID) + )[1].split("\n")[0] + yield model_evaluation_id + + +def test_get_model_evaluation(capsys, model_evaluation_id): + get_model_evaluation.get_model_evaluation( + PROJECT_ID, MODEL_ID, model_evaluation_id + ) + out, _ = capsys.readouterr() + assert "Model evaluation name: " in out diff --git a/automl/beta/get_model_test.py b/automl/beta/get_model_test.py new file mode 100644 index 00000000000..237ad6daaff --- /dev/null +++ b/automl/beta/get_model_test.py @@ -0,0 +1,26 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import get_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["ENTITY_EXTRACTION_MODEL_ID"] + + +def test_get_model(capsys): + get_model.get_model(PROJECT_ID, MODEL_ID) + out, _ = capsys.readouterr() + assert "Model id: " in out diff --git a/automl/beta/get_operation_status.py b/automl/beta/get_operation_status.py new file mode 100644 index 00000000000..612acbaae0d --- /dev/null +++ b/automl/beta/get_operation_status.py @@ -0,0 +1,34 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START automl_get_operation_status_beta] +from google.cloud import automl_v1beta1 as automl + + +def get_operation_status( + operation_full_id="projects/YOUR_PROJECT_ID/locations/us-central1/" + "operations/YOUR_OPERATION_ID", +): + """Get operation status.""" + client = automl.AutoMlClient() + + # Get the latest state of a long-running operation. + response = client._transport.operations_client.get_operation( + operation_full_id + ) + + print("Name: {}".format(response.name)) + print("Operation details:") + print(response) +# [END automl_get_operation_status_beta] diff --git a/automl/beta/get_operation_status_test.py b/automl/beta/get_operation_status_test.py new file mode 100644 index 00000000000..eca99033940 --- /dev/null +++ b/automl/beta/get_operation_status_test.py @@ -0,0 +1,40 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud import automl_v1beta1 as automl +import pytest + +import get_operation_status + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +@pytest.fixture(scope="function") +def operation_id(): + client = automl.AutoMlClient() + project_location = f"projects/{PROJECT_ID}/locations/us-central1" + generator = client._transport.operations_client.list_operations( + project_location, filter_="" + ).pages + page = next(generator) + operation = next(page) + yield operation.name + + +def test_get_operation_status(capsys, operation_id): + get_operation_status.get_operation_status(operation_id) + out, _ = capsys.readouterr() + assert "Operation details" in out diff --git a/automl/beta/import_dataset.py b/automl/beta/import_dataset.py new file mode 100644 index 00000000000..d091061557c --- /dev/null +++ b/automl/beta/import_dataset.py @@ -0,0 +1,40 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# [START automl_import_data_beta] +from google.cloud import automl_v1beta1 as automl + + +def import_dataset( + project_id="YOUR_PROJECT_ID", + dataset_id="YOUR_DATASET_ID", + path="gs://YOUR_BUCKET_ID/path/to/data.csv", +): + """Import a dataset.""" + client = automl.AutoMlClient() + # Get the full path of the dataset. + dataset_full_id = client.dataset_path( + project_id, "us-central1", dataset_id + ) + # Get the multiple Google Cloud Storage URIs + input_uris = path.split(",") + gcs_source = automl.GcsSource(input_uris=input_uris) + input_config = automl.InputConfig(gcs_source=gcs_source) + # Import data from the input URI + response = client.import_data(name=dataset_full_id, input_config=input_config) + + print("Processing import...") + print("Data imported. {}".format(response.result())) +# [END automl_import_data_beta] diff --git a/automl/beta/import_dataset_test.py b/automl/beta/import_dataset_test.py new file mode 100644 index 00000000000..05262094fb1 --- /dev/null +++ b/automl/beta/import_dataset_test.py @@ -0,0 +1,41 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import import_dataset + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +BUCKET_ID = "{}-lcm".format(PROJECT_ID) +DATASET_ID = "VCN0000000000000000000" + + +def test_import_dataset(capsys): + # As importing a dataset can take a long time and only four operations can + # be run on a dataset at once. Try to import into a nonexistent dataset and + # confirm that the dataset was not found, but other elements of the request + # were valid. + try: + data = "gs://{}/video-classification/dataset.csv".format(BUCKET_ID) + import_dataset.import_dataset(PROJECT_ID, DATASET_ID, data) + out, _ = capsys.readouterr() + assert ( + "The Dataset doesn't exist or is inaccessible for use with AutoMl." + in out + ) + except Exception as e: + assert ( + "The Dataset doesn't exist or is inaccessible for use with AutoMl." + in e.message + ) diff --git a/automl/beta/list_datasets.py b/automl/beta/list_datasets.py new file mode 100644 index 00000000000..ad3042b5ad9 --- /dev/null +++ b/automl/beta/list_datasets.py @@ -0,0 +1,52 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# [START automl_video_classification_list_datasets_beta] +# [START automl_video_object_tracking_list_datasets_beta] +from google.cloud import automl_v1beta1 as automl + + +def list_datasets(project_id="YOUR_PROJECT_ID"): + """List datasets.""" + client = automl.AutoMlClient() + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + + # List all the datasets available in the region. + request = automl.ListDatasetsRequest(parent=project_location, filter="") + response = client.list_datasets(request=request) + + print("List of datasets:") + for dataset in response: + print("Dataset name: {}".format(dataset.name)) + print("Dataset id: {}".format(dataset.name.split("/")[-1])) + print("Dataset display name: {}".format(dataset.display_name)) + print("Dataset create time: {}".format(dataset.create_time)) + # [END automl_video_object_tracking_list_datasets_beta] + + print( + "Video classification dataset metadata: {}".format( + dataset.video_classification_dataset_metadata + ) + ) + # [END automl_video_classification_list_datasets_beta] + + # [START automl_video_object_tracking_list_datasets_beta] + print( + "Video object tracking dataset metadata: {}".format( + dataset.video_object_tracking_dataset_metadata + ) + ) + # [END automl_video_object_tracking_list_datasets_beta] diff --git a/automl/beta/list_datasets_test.py b/automl/beta/list_datasets_test.py new file mode 100644 index 00000000000..7057af815d1 --- /dev/null +++ b/automl/beta/list_datasets_test.py @@ -0,0 +1,27 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import list_datasets + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = os.environ["ENTITY_EXTRACTION_DATASET_ID"] + + +def test_list_dataset(capsys): + # list datasets + list_datasets.list_datasets(PROJECT_ID) + out, _ = capsys.readouterr() + assert "Dataset id: {}".format(DATASET_ID) in out diff --git a/automl/beta/list_models.py b/automl/beta/list_models.py new file mode 100644 index 00000000000..684e2ec25e8 --- /dev/null +++ b/automl/beta/list_models.py @@ -0,0 +1,46 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def list_models(project_id): + """List models.""" + # [START automl_list_models_beta] + from google.cloud import automl_v1beta1 as automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + + client = automl.AutoMlClient() + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + request = automl.ListModelsRequest(parent=project_location, filter="") + response = client.list_models(request=request) + + print("List of models:") + for model in response: + # Display the model information. + if ( + model.deployment_state + == automl.Model.DeploymentState.DEPLOYED + ): + deployment_state = "deployed" + else: + deployment_state = "undeployed" + + print("Model name: {}".format(model.name)) + print("Model id: {}".format(model.name.split("/")[-1])) + print("Model display name: {}".format(model.display_name)) + print("Model create time: {}".format(model.create_time)) + print("Model deployment state: {}".format(deployment_state)) + # [END automl_list_models_beta] diff --git a/automl/beta/list_models_test.py b/automl/beta/list_models_test.py new file mode 100644 index 00000000000..75f8c40a038 --- /dev/null +++ b/automl/beta/list_models_test.py @@ -0,0 +1,25 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import list_models + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +def test_list_models(capsys): + list_models.list_models(PROJECT_ID) + out, _ = capsys.readouterr() + assert "Model id: " in out diff --git a/automl/beta/requirements-test.txt b/automl/beta/requirements-test.txt new file mode 100644 index 00000000000..49780e03569 --- /dev/null +++ b/automl/beta/requirements-test.txt @@ -0,0 +1 @@ +pytest==7.2.0 diff --git a/automl/beta/requirements.txt b/automl/beta/requirements.txt new file mode 100644 index 00000000000..53c7a53d7d7 --- /dev/null +++ b/automl/beta/requirements.txt @@ -0,0 +1 @@ +google-cloud-automl==2.8.3 diff --git a/automl/beta/set_endpoint.py b/automl/beta/set_endpoint.py new file mode 100644 index 00000000000..f335e35eb6f --- /dev/null +++ b/automl/beta/set_endpoint.py @@ -0,0 +1,44 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def set_endpoint(project_id): + """Change your endpoint""" + # [START automl_set_endpoint] + from google.cloud import automl_v1beta1 as automl + + # You must first create a dataset, using the `eu` endpoint, before you can + # call other operations such as: list, get, import, delete, etc. + client_options = {'api_endpoint': 'eu-automl.googleapis.com:443'} + + # Instantiates a client + client = automl.AutoMlClient(client_options=client_options) + + # A resource that represents Google Cloud Platform location. + # project_id = 'YOUR_PROJECT_ID' + project_location = f"projects/{project_id}/locations/eu" + # [END automl_set_endpoint] + + # List all the datasets available + # Note: Create a dataset in `eu`, before calling `list_datasets`. + request = automl.ListDatasetsRequest( + parent=project_location, + filter="" + ) + response = client.list_datasets( + request=request + ) + + for dataset in response: + print(dataset) diff --git a/automl/beta/set_endpoint_test.py b/automl/beta/set_endpoint_test.py new file mode 100644 index 00000000000..02339311823 --- /dev/null +++ b/automl/beta/set_endpoint_test.py @@ -0,0 +1,28 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import set_endpoint + + +PROJECT_ID = os.environ['GOOGLE_CLOUD_PROJECT'] + + +def test_set_endpoint(capsys): + set_endpoint.set_endpoint(PROJECT_ID) + + out, _ = capsys.readouterr() + # Look for the display name + assert 'do_not_delete_me' in out diff --git a/automl/beta/video_classification_create_dataset.py b/automl/beta/video_classification_create_dataset.py new file mode 100644 index 00000000000..7d756b099c2 --- /dev/null +++ b/automl/beta/video_classification_create_dataset.py @@ -0,0 +1,46 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +# [START automl_video_classification_create_dataset_beta] +from google.cloud import automl_v1beta1 as automl + + +def create_dataset( + project_id="YOUR_PROJECT_ID", display_name="your_datasets_display_name" +): + """Create a automl video classification dataset.""" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + metadata = automl.VideoClassificationDatasetMetadata() + dataset = automl.Dataset( + display_name=display_name, + video_classification_dataset_metadata=metadata, + ) + + # Create a dataset with the dataset metadata in the region. + created_dataset = client.create_dataset(parent=project_location, dataset=dataset) + + # Display the dataset information + print("Dataset name: {}".format(created_dataset.name)) + + # To get the dataset id, you have to parse it out of the `name` field. + # As dataset Ids are required for other methods. + # Name Form: + # `projects/{project_id}/locations/{location_id}/datasets/{dataset_id}` + print("Dataset id: {}".format(created_dataset.name.split("/")[-1])) +# [END automl_video_classification_create_dataset_beta] diff --git a/automl/beta/video_classification_create_dataset_test.py b/automl/beta/video_classification_create_dataset_test.py new file mode 100644 index 00000000000..9eb994d0084 --- /dev/null +++ b/automl/beta/video_classification_create_dataset_test.py @@ -0,0 +1,52 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import uuid + +from google.cloud import automl_v1beta1 as automl +import pytest + +import video_classification_create_dataset + + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = None + + +@pytest.fixture(scope="function", autouse=True) +def teardown(): + yield + + # Delete the created dataset + client = automl.AutoMlClient() + dataset_full_id = client.dataset_path( + PROJECT_ID, "us-central1", DATASET_ID + ) + response = client.delete_dataset(name=dataset_full_id) + response.result() + + +def test_video_classification_create_dataset(capsys): + # create dataset + dataset_name = "test_{}".format(uuid.uuid4()).replace("-", "")[:32] + video_classification_create_dataset.create_dataset( + PROJECT_ID, dataset_name + ) + out, _ = capsys.readouterr() + assert "Dataset id: " in out + + # Get the dataset id for deletion + global DATASET_ID + DATASET_ID = out.splitlines()[1].split()[2] diff --git a/automl/beta/video_classification_create_model.py b/automl/beta/video_classification_create_model.py new file mode 100644 index 00000000000..58e0ab32033 --- /dev/null +++ b/automl/beta/video_classification_create_model.py @@ -0,0 +1,43 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START automl_video_classification_create_model_beta] +from google.cloud import automl_v1beta1 as automl + + +def create_model( + project_id="YOUR_PROJECT_ID", + dataset_id="YOUR_DATASET_ID", + display_name="your_models_display_name", +): + """Create a automl video classification model.""" + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + # Leave model unset to use the default base model provided by Google + metadata = automl.VideoClassificationModelMetadata() + model = automl.Model( + display_name=display_name, + dataset_id=dataset_id, + video_classification_model_metadata=metadata, + ) + + # Create a model with the model metadata in the region. + response = client.create_model(parent=project_location, model=model) + + print("Training operation name: {}".format(response.operation.name)) + print("Training started...") +# [END automl_video_classification_create_model_beta] + return response diff --git a/automl/beta/video_classification_create_model_test.py b/automl/beta/video_classification_create_model_test.py new file mode 100644 index 00000000000..148d2d5b774 --- /dev/null +++ b/automl/beta/video_classification_create_model_test.py @@ -0,0 +1,32 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import video_classification_create_model + +PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] +DATASET_ID = "VCN00000000000000000" +OPERATION_ID = None + + +def test_video_classification_create_model(capsys): + try: + video_classification_create_model.create_model( + PROJECT_ID, DATASET_ID, "video_class_test_create_model" + ) + out, _ = capsys.readouterr() + assert "Dataset does not exist." in out + except Exception as e: + assert "Dataset does not exist." in e.message diff --git a/automl/beta/video_object_tracking_create_dataset.py b/automl/beta/video_object_tracking_create_dataset.py new file mode 100644 index 00000000000..c99d5c0205a --- /dev/null +++ b/automl/beta/video_object_tracking_create_dataset.py @@ -0,0 +1,38 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START automl_video_object_tracking_create_dataset_beta] +from google.cloud import automl_v1beta1 as automl + + +def create_dataset( + project_id="YOUR_PROJECT_ID", display_name="your_datasets_display_name" +): + """Create a automl video object tracking dataset.""" + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + metadata = automl.VideoObjectTrackingDatasetMetadata() + dataset = automl.Dataset( + display_name=display_name, + video_object_tracking_dataset_metadata=metadata, + ) + + # Create a dataset with the dataset metadata in the region. + created_dataset = client.create_dataset(parent=project_location, dataset=dataset) + # Display the dataset information + print("Dataset name: {}".format(created_dataset.name)) + print("Dataset id: {}".format(created_dataset.name.split("/")[-1])) +# [END automl_video_object_tracking_create_dataset_beta] diff --git a/automl/beta/video_object_tracking_create_dataset_test.py b/automl/beta/video_object_tracking_create_dataset_test.py new file mode 100644 index 00000000000..1ef744cba3f --- /dev/null +++ b/automl/beta/video_object_tracking_create_dataset_test.py @@ -0,0 +1,51 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +import uuid + +from google.cloud import automl_v1beta1 as automl +import pytest + +import video_object_tracking_create_dataset + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = None + + +@pytest.fixture(scope="function", autouse=True) +def teardown(): + yield + + # Delete the created dataset + client = automl.AutoMlClient() + dataset_full_id = client.dataset_path( + PROJECT_ID, "us-central1", DATASET_ID + ) + response = client.delete_dataset(name=dataset_full_id) + response.result() + + +def test_video_classification_create_dataset(capsys): + # create dataset + dataset_name = "test_{}".format(uuid.uuid4()).replace("-", "")[:32] + video_object_tracking_create_dataset.create_dataset( + PROJECT_ID, dataset_name + ) + out, _ = capsys.readouterr() + assert "Dataset id: " in out + + # Get the dataset id for deletion + global DATASET_ID + DATASET_ID = out.splitlines()[1].split()[2] diff --git a/automl/beta/video_object_tracking_create_model.py b/automl/beta/video_object_tracking_create_model.py new file mode 100644 index 00000000000..38ce963cb04 --- /dev/null +++ b/automl/beta/video_object_tracking_create_model.py @@ -0,0 +1,42 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +# [START automl_video_object_tracking_create_model_beta] +from google.cloud import automl_v1beta1 as automl + + +def create_model( + project_id="YOUR_PROJECT_ID", + dataset_id="YOUR_DATASET_ID", + display_name="your_models_display_name", +): + """Create a automl video classification model.""" + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform loacation. + project_location = f"projects/{project_id}/locations/us-central1" + # Leave model unset to use the default base model provided by Google + metadata = automl.VideoObjectTrackingModelMetadata() + model = automl.Model( + display_name=display_name, + dataset_id=dataset_id, + video_object_tracking_model_metadata=metadata, + ) + + # Create a model with the model metadata in the region. + response = client.create_model(parent=project_location, model=model) + + print("Training operation name: {}".format(response.operation.name)) + print("Training started...") +# [END automl_video_object_tracking_create_model_beta] diff --git a/automl/beta/video_object_tracking_create_model_test.py b/automl/beta/video_object_tracking_create_model_test.py new file mode 100644 index 00000000000..f966b21db3a --- /dev/null +++ b/automl/beta/video_object_tracking_create_model_test.py @@ -0,0 +1,32 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import video_object_tracking_create_model + +PROJECT_ID = os.environ["GOOGLE_CLOUD_PROJECT"] +DATASET_ID = "VOT00000000000000000000" +OPERATION_ID = None + + +def test_video_classification_create_model(capsys): + try: + video_object_tracking_create_model.create_model( + PROJECT_ID, DATASET_ID, "video_object_test_create_model" + ) + out, _ = capsys.readouterr() + assert "Dataset does not exist." in out + except Exception as e: + assert "Dataset does not exist." in e.message diff --git a/automl/snippets/batch_predict.py b/automl/snippets/batch_predict.py new file mode 100644 index 00000000000..5b5f810b4ed --- /dev/null +++ b/automl/snippets/batch_predict.py @@ -0,0 +1,46 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def batch_predict(project_id, model_id, input_uri, output_uri): + """Batch predict""" + # [START automl_batch_predict] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + # input_uri = "gs://YOUR_BUCKET_ID/path/to/your/input/csv_or_jsonl" + # output_uri = "gs://YOUR_BUCKET_ID/path/to/save/results/" + + prediction_client = automl.PredictionServiceClient() + + # Get the full path of the model. + model_full_id = f"projects/{project_id}/locations/us-central1/models/{model_id}" + + gcs_source = automl.GcsSource(input_uris=[input_uri]) + + input_config = automl.BatchPredictInputConfig(gcs_source=gcs_source) + gcs_destination = automl.GcsDestination(output_uri_prefix=output_uri) + output_config = automl.BatchPredictOutputConfig(gcs_destination=gcs_destination) + + response = prediction_client.batch_predict( + name=model_full_id, input_config=input_config, output_config=output_config + ) + + print("Waiting for operation to complete...") + print( + f"Batch Prediction results saved to Cloud Storage bucket. {response.result()}" + ) + # [END automl_batch_predict] diff --git a/automl/snippets/batch_predict_test.py b/automl/snippets/batch_predict_test.py new file mode 100644 index 00000000000..483ea5187cc --- /dev/null +++ b/automl/snippets/batch_predict_test.py @@ -0,0 +1,37 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific ladnguage governing permissions and +# limitations under the License. + +import datetime +import os + +import batch_predict + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +BUCKET_ID = "{}-lcm".format(PROJECT_ID) +MODEL_ID = "TEN0000000000000000000" +PREFIX = "TEST_EXPORT_OUTPUT_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + + +def test_batch_predict(capsys): + # As batch prediction can take a long time. Try to batch predict on a model + # and confirm that the model was not found, but other elements of the + # request were valid. + try: + input_uri = "gs://{}/entity-extraction/input.jsonl".format(BUCKET_ID) + output_uri = "gs://{}/{}/".format(BUCKET_ID, PREFIX) + batch_predict.batch_predict(PROJECT_ID, MODEL_ID, input_uri, output_uri) + out, _ = capsys.readouterr() + assert "does not exist" in out + except Exception as e: + assert "does not exist" in e.message diff --git a/automl/snippets/delete_dataset.py b/automl/snippets/delete_dataset.py new file mode 100644 index 00000000000..284ca704d9a --- /dev/null +++ b/automl/snippets/delete_dataset.py @@ -0,0 +1,31 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def delete_dataset(project_id, dataset_id): + """Delete a dataset.""" + # [START automl_delete_dataset] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # dataset_id = "YOUR_DATASET_ID" + + client = automl.AutoMlClient() + # Get the full path of the dataset + dataset_full_id = client.dataset_path(project_id, "us-central1", dataset_id) + response = client.delete_dataset(name=dataset_full_id) + + print("Dataset deleted. {}".format(response.result())) + # [END automl_delete_dataset] diff --git a/automl/snippets/delete_dataset_test.py b/automl/snippets/delete_dataset_test.py new file mode 100644 index 00000000000..d085c5450ac --- /dev/null +++ b/automl/snippets/delete_dataset_test.py @@ -0,0 +1,46 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os + +from google.cloud import automl +import pytest + +import delete_dataset + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +BUCKET_ID = "{}-lcm".format(PROJECT_ID) + + +@pytest.fixture(scope="function") +def dataset_id(): + client = automl.AutoMlClient() + project_location = f"projects/{PROJECT_ID}/locations/us-central1" + display_name = "test_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + metadata = automl.TextExtractionDatasetMetadata() + dataset = automl.Dataset( + display_name=display_name, text_extraction_dataset_metadata=metadata + ) + response = client.create_dataset(parent=project_location, dataset=dataset) + dataset_id = response.result().name.split("/")[-1] + + yield dataset_id + + +def test_delete_dataset(capsys, dataset_id): + # delete dataset + delete_dataset.delete_dataset(PROJECT_ID, dataset_id) + out, _ = capsys.readouterr() + assert "Dataset deleted." in out diff --git a/automl/snippets/delete_model.py b/automl/snippets/delete_model.py new file mode 100644 index 00000000000..1675bd2c480 --- /dev/null +++ b/automl/snippets/delete_model.py @@ -0,0 +1,31 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def delete_model(project_id, model_id): + """Delete a model.""" + # [START automl_delete_model] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + + client = automl.AutoMlClient() + # Get the full path of the model. + model_full_id = client.model_path(project_id, "us-central1", model_id) + response = client.delete_model(name=model_full_id) + + print("Model deleted. {}".format(response.result())) + # [END automl_delete_model] diff --git a/automl/snippets/delete_model_test.py b/automl/snippets/delete_model_test.py new file mode 100644 index 00000000000..8721e14b44b --- /dev/null +++ b/automl/snippets/delete_model_test.py @@ -0,0 +1,31 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import delete_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +def test_delete_model(capsys): + # As model creation can take many hours, instead try to delete a + # nonexistent model and confirm that the model was not found, but other + # elements of the request were valid. + try: + delete_model.delete_model(PROJECT_ID, "TRL0000000000000000000") + out, _ = capsys.readouterr() + assert "The model does not exist" in out + except Exception as e: + assert "The model does not exist" in e.message diff --git a/automl/snippets/deploy_model.py b/automl/snippets/deploy_model.py new file mode 100644 index 00000000000..12518fefb89 --- /dev/null +++ b/automl/snippets/deploy_model.py @@ -0,0 +1,31 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def deploy_model(project_id, model_id): + """Deploy a model.""" + # [START automl_deploy_model] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + + client = automl.AutoMlClient() + # Get the full path of the model. + model_full_id = client.model_path(project_id, "us-central1", model_id) + response = client.deploy_model(name=model_full_id) + + print(f"Model deployment finished. {response.result()}") + # [END automl_deploy_model] diff --git a/automl/snippets/deploy_model_test.py b/automl/snippets/deploy_model_test.py new file mode 100644 index 00000000000..d8a72f1eee0 --- /dev/null +++ b/automl/snippets/deploy_model_test.py @@ -0,0 +1,35 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytest + +import deploy_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = "TRL0000000000000000000" + + +@pytest.mark.slow +def test_deploy_model(capsys): + # As model deployment can take a long time, instead try to deploy a + # nonexistent model and confirm that the model was not found, but other + # elements of the request were valid. + try: + deploy_model.deploy_model(PROJECT_ID, MODEL_ID) + out, _ = capsys.readouterr() + assert "The model does not exist" in out + except Exception as e: + assert "The model does not exist" in e.message diff --git a/automl/snippets/export_dataset.py b/automl/snippets/export_dataset.py new file mode 100644 index 00000000000..bd68ca3116a --- /dev/null +++ b/automl/snippets/export_dataset.py @@ -0,0 +1,36 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def export_dataset(project_id, dataset_id, gcs_uri): + """Export a dataset.""" + # [START automl_export_dataset] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # dataset_id = "YOUR_DATASET_ID" + # gcs_uri = "gs://YOUR_BUCKET_ID/path/to/export/" + + client = automl.AutoMlClient() + + # Get the full path of the dataset + dataset_full_id = client.dataset_path(project_id, "us-central1", dataset_id) + + gcs_destination = automl.GcsDestination(output_uri_prefix=gcs_uri) + output_config = automl.OutputConfig(gcs_destination=gcs_destination) + + response = client.export_data(name=dataset_full_id, output_config=output_config) + print(f"Dataset exported. {response.result()}") + # [END automl_export_dataset] diff --git a/automl/snippets/export_dataset_test.py b/automl/snippets/export_dataset_test.py new file mode 100644 index 00000000000..62b899b06c5 --- /dev/null +++ b/automl/snippets/export_dataset_test.py @@ -0,0 +1,43 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os + +import export_dataset + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +BUCKET_ID = "{}-lcm".format(PROJECT_ID) +PREFIX = "TEST_EXPORT_OUTPUT_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") +DATASET_ID = "TEN0000000000000000000" + + +def test_export_dataset(capsys): + # As exporting a dataset can take a long time and only one operation can be + # run on a dataset at once. Try to export a nonexistent dataset and confirm + # that the dataset was not found, but other elements of the request were\ + # valid. + try: + export_dataset.export_dataset( + PROJECT_ID, DATASET_ID, "gs://{}/{}/".format(BUCKET_ID, PREFIX) + ) + out, _ = capsys.readouterr() + assert ( + "The Dataset doesn't exist or is inaccessible for use with AutoMl." in out + ) + except Exception as e: + assert ( + "The Dataset doesn't exist or is inaccessible for use with AutoMl." + in e.message + ) diff --git a/automl/snippets/get_dataset.py b/automl/snippets/get_dataset.py new file mode 100644 index 00000000000..6fa55a2ec96 --- /dev/null +++ b/automl/snippets/get_dataset.py @@ -0,0 +1,96 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def get_dataset(project_id, dataset_id): + """Get a dataset.""" + # [START automl_language_entity_extraction_get_dataset] + # [START automl_language_sentiment_analysis_get_dataset] + # [START automl_language_text_classification_get_dataset] + # [START automl_translate_get_dataset] + # [START automl_vision_classification_get_dataset] + # [START automl_vision_object_detection_get_dataset] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # dataset_id = "YOUR_DATASET_ID" + + client = automl.AutoMlClient() + # Get the full path of the dataset + dataset_full_id = client.dataset_path(project_id, "us-central1", dataset_id) + dataset = client.get_dataset(name=dataset_full_id) + + # Display the dataset information + print("Dataset name: {}".format(dataset.name)) + print("Dataset id: {}".format(dataset.name.split("/")[-1])) + print("Dataset display name: {}".format(dataset.display_name)) + print("Dataset create time: {}".format(dataset.create_time)) + # [END automl_language_sentiment_analysis_get_dataset] + # [END automl_language_text_classification_get_dataset] + # [END automl_translate_get_dataset] + # [END automl_vision_classification_get_dataset] + # [END automl_vision_object_detection_get_dataset] + print( + "Text extraction dataset metadata: {}".format( + dataset.text_extraction_dataset_metadata + ) + ) + # [END automl_language_entity_extraction_get_dataset] + + # [START automl_language_sentiment_analysis_get_dataset] + print( + "Text sentiment dataset metadata: {}".format( + dataset.text_sentiment_dataset_metadata + ) + ) + # [END automl_language_sentiment_analysis_get_dataset] + + # [START automl_language_text_classification_get_dataset] + print( + "Text classification dataset metadata: {}".format( + dataset.text_classification_dataset_metadata + ) + ) + # [END automl_language_text_classification_get_dataset] + + # [START automl_translate_get_dataset] + print("Translation dataset metadata:") + print( + "\tsource_language_code: {}".format( + dataset.translation_dataset_metadata.source_language_code + ) + ) + print( + "\ttarget_language_code: {}".format( + dataset.translation_dataset_metadata.target_language_code + ) + ) + # [END automl_translate_get_dataset] + + # [START automl_vision_classification_get_dataset] + print( + "Image classification dataset metadata: {}".format( + dataset.image_classification_dataset_metadata + ) + ) + # [END automl_vision_classification_get_dataset] + + # [START automl_vision_object_detection_get_dataset] + print( + "Image object detection dataset metadata: {}".format( + dataset.image_object_detection_dataset_metadata + ) + ) + # [END automl_vision_object_detection_get_dataset] diff --git a/automl/snippets/get_dataset_test.py b/automl/snippets/get_dataset_test.py new file mode 100644 index 00000000000..3cc688eb3f9 --- /dev/null +++ b/automl/snippets/get_dataset_test.py @@ -0,0 +1,26 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import get_dataset + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = os.environ["ENTITY_EXTRACTION_DATASET_ID"] + + +def test_get_dataset(capsys): + get_dataset.get_dataset(PROJECT_ID, DATASET_ID) + out, _ = capsys.readouterr() + assert "Dataset name: " in out diff --git a/automl/snippets/get_model.py b/automl/snippets/get_model.py new file mode 100644 index 00000000000..2c686d7e4a5 --- /dev/null +++ b/automl/snippets/get_model.py @@ -0,0 +1,42 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def get_model(project_id, model_id): + """Get a model.""" + # [START automl_get_model] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + + client = automl.AutoMlClient() + # Get the full path of the model. + model_full_id = client.model_path(project_id, "us-central1", model_id) + model = client.get_model(name=model_full_id) + + # Retrieve deployment state. + if model.deployment_state == automl.Model.DeploymentState.DEPLOYED: + deployment_state = "deployed" + else: + deployment_state = "undeployed" + + # Display the model information. + print("Model name: {}".format(model.name)) + print("Model id: {}".format(model.name.split("/")[-1])) + print("Model display name: {}".format(model.display_name)) + print("Model create time: {}".format(model.create_time)) + print("Model deployment state: {}".format(deployment_state)) + # [END automl_get_model] diff --git a/automl/snippets/get_model_evaluation.py b/automl/snippets/get_model_evaluation.py new file mode 100644 index 00000000000..1f526664bf3 --- /dev/null +++ b/automl/snippets/get_model_evaluation.py @@ -0,0 +1,87 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def get_model_evaluation(project_id, model_id, model_evaluation_id): + """Get model evaluation.""" + # [START automl_language_entity_extraction_get_model_evaluation] + # [START automl_language_sentiment_analysis_get_model_evaluation] + # [START automl_language_text_classification_get_model_evaluation] + # [START automl_translate_get_model_evaluation] + # [START automl_vision_classification_get_model_evaluation] + # [START automl_vision_object_detection_get_model_evaluation] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + # model_evaluation_id = "YOUR_MODEL_EVALUATION_ID" + + client = automl.AutoMlClient() + # Get the full path of the model evaluation. + model_path = client.model_path(project_id, "us-central1", model_id) + model_evaluation_full_id = f"{model_path}/modelEvaluations/{model_evaluation_id}" + + # Get complete detail of the model evaluation. + response = client.get_model_evaluation(name=model_evaluation_full_id) + + print("Model evaluation name: {}".format(response.name)) + print("Model annotation spec id: {}".format(response.annotation_spec_id)) + print("Create Time: {}".format(response.create_time)) + print("Evaluation example count: {}".format(response.evaluated_example_count)) + # [END automl_language_sentiment_analysis_get_model_evaluation] + # [END automl_language_text_classification_get_model_evaluation] + # [END automl_translate_get_model_evaluation] + # [END automl_vision_classification_get_model_evaluation] + # [END automl_vision_object_detection_get_model_evaluation] + print( + "Entity extraction model evaluation metrics: {}".format( + response.text_extraction_evaluation_metrics + ) + ) + # [END automl_language_entity_extraction_get_model_evaluation] + + # [START automl_language_sentiment_analysis_get_model_evaluation] + print( + "Sentiment analysis model evaluation metrics: {}".format( + response.text_sentiment_evaluation_metrics + ) + ) + # [END automl_language_sentiment_analysis_get_model_evaluation] + + # [START automl_language_text_classification_get_model_evaluation] + # [START automl_vision_classification_get_model_evaluation] + print( + "Classification model evaluation metrics: {}".format( + response.classification_evaluation_metrics + ) + ) + # [END automl_language_text_classification_get_model_evaluation] + # [END automl_vision_classification_get_model_evaluation] + + # [START automl_translate_get_model_evaluation] + print( + "Translation model evaluation metrics: {}".format( + response.translation_evaluation_metrics + ) + ) + # [END automl_translate_get_model_evaluation] + + # [START automl_vision_object_detection_get_model_evaluation] + print( + "Object detection model evaluation metrics: {}".format( + response.image_object_detection_evaluation_metrics + ) + ) + # [END automl_vision_object_detection_get_model_evaluation] diff --git a/automl/snippets/get_model_evaluation_test.py b/automl/snippets/get_model_evaluation_test.py new file mode 100644 index 00000000000..7d694e55f72 --- /dev/null +++ b/automl/snippets/get_model_evaluation_test.py @@ -0,0 +1,43 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud import automl +import pytest + +import get_model_evaluation + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["ENTITY_EXTRACTION_MODEL_ID"] + + +@pytest.fixture(scope="function") +def model_evaluation_id(): + client = automl.AutoMlClient() + model_full_id = client.model_path(PROJECT_ID, "us-central1", MODEL_ID) + evaluation = None + for e in client.list_model_evaluations(parent=model_full_id, filter=""): + evaluation = e + break + model_evaluation_id = evaluation.name.split( + "{}/modelEvaluations/".format(MODEL_ID) + )[1].split("\n")[0] + yield model_evaluation_id + + +def test_get_model_evaluation(capsys, model_evaluation_id): + get_model_evaluation.get_model_evaluation(PROJECT_ID, MODEL_ID, model_evaluation_id) + out, _ = capsys.readouterr() + assert "Model evaluation name: " in out diff --git a/automl/snippets/get_model_test.py b/automl/snippets/get_model_test.py new file mode 100644 index 00000000000..c146e18cbfd --- /dev/null +++ b/automl/snippets/get_model_test.py @@ -0,0 +1,26 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import get_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["ENTITY_EXTRACTION_MODEL_ID"] + + +def test_get_model(capsys): + get_model.get_model(PROJECT_ID, MODEL_ID) + out, _ = capsys.readouterr() + assert "Model id: " in out diff --git a/automl/snippets/get_operation_status.py b/automl/snippets/get_operation_status.py new file mode 100644 index 00000000000..5d17dd5fc96 --- /dev/null +++ b/automl/snippets/get_operation_status.py @@ -0,0 +1,32 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def get_operation_status(operation_full_id): + """Get operation status.""" + # [START automl_get_operation_status] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # operation_full_id = \ + # "projects/[projectId]/locations/us-central1/operations/[operationId]" + + client = automl.AutoMlClient() + # Get the latest state of a long-running operation. + response = client._transport.operations_client.get_operation(operation_full_id) + + print("Name: {}".format(response.name)) + print("Operation details:") + print(response) + # [END automl_get_operation_status] diff --git a/automl/snippets/get_operation_status_test.py b/automl/snippets/get_operation_status_test.py new file mode 100644 index 00000000000..5f7f0b4161e --- /dev/null +++ b/automl/snippets/get_operation_status_test.py @@ -0,0 +1,41 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud import automl +import pytest + +import get_operation_status + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +@pytest.fixture(scope="function") +def operation_id(): + client = automl.AutoMlClient() + project_location = f"projects/{PROJECT_ID}/locations/us-central1" + + generator = client._transport.operations_client.list_operations( + project_location, filter_="" + ).pages + page = next(generator) + operation = next(page) + yield operation.name + + +def test_get_operation_status(capsys, operation_id): + get_operation_status.get_operation_status(operation_id) + out, _ = capsys.readouterr() + assert "Operation details" in out diff --git a/automl/snippets/import_dataset.py b/automl/snippets/import_dataset.py new file mode 100644 index 00000000000..cdda1431fee --- /dev/null +++ b/automl/snippets/import_dataset.py @@ -0,0 +1,38 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def import_dataset(project_id, dataset_id, path): + """Import a dataset.""" + # [START automl_import_data] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # dataset_id = "YOUR_DATASET_ID" + # path = "gs://YOUR_BUCKET_ID/path/to/data.csv" + + client = automl.AutoMlClient() + # Get the full path of the dataset. + dataset_full_id = client.dataset_path(project_id, "us-central1", dataset_id) + # Get the multiple Google Cloud Storage URIs + input_uris = path.split(",") + gcs_source = automl.GcsSource(input_uris=input_uris) + input_config = automl.InputConfig(gcs_source=gcs_source) + # Import data from the input URI + response = client.import_data(name=dataset_full_id, input_config=input_config) + + print("Processing import...") + print("Data imported. {}".format(response.result())) + # [END automl_import_data] diff --git a/automl/snippets/import_dataset_test.py b/automl/snippets/import_dataset_test.py new file mode 100644 index 00000000000..2b4f578f7d6 --- /dev/null +++ b/automl/snippets/import_dataset_test.py @@ -0,0 +1,40 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import import_dataset + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +BUCKET_ID = "{}-lcm".format(PROJECT_ID) +DATASET_ID = "TEN0000000000000000000" + + +def test_import_dataset(capsys): + # As importing a dataset can take a long time and only four operations can + # be run on a dataset at once. Try to import into a nonexistent dataset and + # confirm that the dataset was not found, but other elements of the request + # were valid. + try: + data = "gs://{}/sentiment-analysis/dataset.csv".format(BUCKET_ID) + import_dataset.import_dataset(PROJECT_ID, DATASET_ID, data) + out, _ = capsys.readouterr() + assert ( + "The Dataset doesn't exist or is inaccessible for use with AutoMl." in out + ) + except Exception as e: + assert ( + "The Dataset doesn't exist or is inaccessible for use with AutoMl." + in e.message + ) diff --git a/automl/snippets/language_entity_extraction_create_dataset.py b/automl/snippets/language_entity_extraction_create_dataset.py new file mode 100644 index 00000000000..34d7ae5b91c --- /dev/null +++ b/automl/snippets/language_entity_extraction_create_dataset.py @@ -0,0 +1,42 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_dataset(project_id, display_name): + """Create a dataset.""" + # [START automl_language_entity_extraction_create_dataset] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # display_name = "YOUR_DATASET_NAME" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + metadata = automl.TextExtractionDatasetMetadata() + dataset = automl.Dataset( + display_name=display_name, text_extraction_dataset_metadata=metadata + ) + + # Create a dataset with the dataset metadata in the region. + response = client.create_dataset(parent=project_location, dataset=dataset) + + created_dataset = response.result() + + # Display the dataset information + print("Dataset name: {}".format(created_dataset.name)) + print("Dataset id: {}".format(created_dataset.name.split("/")[-1])) + # [END automl_language_entity_extraction_create_dataset] diff --git a/automl/snippets/language_entity_extraction_create_dataset_test.py b/automl/snippets/language_entity_extraction_create_dataset_test.py new file mode 100644 index 00000000000..c4841cdda4f --- /dev/null +++ b/automl/snippets/language_entity_extraction_create_dataset_test.py @@ -0,0 +1,38 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os + +from google.cloud import automl + +import language_entity_extraction_create_dataset + + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +def test_entity_extraction_create_dataset(capsys): + # create dataset + dataset_name = "test_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + language_entity_extraction_create_dataset.create_dataset(PROJECT_ID, dataset_name) + out, _ = capsys.readouterr() + assert "Dataset id: " in out + + # Delete the created dataset + dataset_id = out.splitlines()[1].split()[2] + client = automl.AutoMlClient() + dataset_full_id = client.dataset_path(PROJECT_ID, "us-central1", dataset_id) + response = client.delete_dataset(name=dataset_full_id) + response.result() diff --git a/automl/snippets/language_entity_extraction_create_model.py b/automl/snippets/language_entity_extraction_create_model.py new file mode 100644 index 00000000000..178ebf9aef0 --- /dev/null +++ b/automl/snippets/language_entity_extraction_create_model.py @@ -0,0 +1,43 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_model(project_id, dataset_id, display_name): + """Create a model.""" + # [START automl_language_entity_extraction_create_model] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # dataset_id = "YOUR_DATASET_ID" + # display_name = "YOUR_MODEL_NAME" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + # Leave model unset to use the default base model provided by Google + metadata = automl.TextExtractionModelMetadata() + model = automl.Model( + display_name=display_name, + dataset_id=dataset_id, + text_extraction_model_metadata=metadata, + ) + + # Create a model with the model metadata in the region. + response = client.create_model(parent=project_location, model=model) + + print("Training operation name: {}".format(response.operation.name)) + print("Training started...") + # [END automl_language_entity_extraction_create_model] diff --git a/automl/snippets/language_entity_extraction_create_model_test.py b/automl/snippets/language_entity_extraction_create_model_test.py new file mode 100644 index 00000000000..0ff74c89b13 --- /dev/null +++ b/automl/snippets/language_entity_extraction_create_model_test.py @@ -0,0 +1,34 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import language_entity_extraction_create_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = "TEN0000000000000000000" + + +def test_entity_extraction_create_model(capsys): + # As entity extraction does not let you cancel model creation, instead try + # to create a model from a nonexistent dataset, but other elements of the + # request were valid. + try: + language_entity_extraction_create_model.create_model( + PROJECT_ID, DATASET_ID, "classification_test_create_model" + ) + out, _ = capsys.readouterr() + assert "Dataset does not exist." in out + except Exception as e: + assert "Dataset does not exist." in e.message diff --git a/automl/snippets/language_entity_extraction_predict.py b/automl/snippets/language_entity_extraction_predict.py new file mode 100644 index 00000000000..f6937d2ac33 --- /dev/null +++ b/automl/snippets/language_entity_extraction_predict.py @@ -0,0 +1,45 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def predict(project_id, model_id, content): + """Predict.""" + # [START automl_language_entity_extraction_predict] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + # content = "text to predict" + + prediction_client = automl.PredictionServiceClient() + + # Get the full path of the model. + model_full_id = automl.AutoMlClient.model_path(project_id, "us-central1", model_id) + + # Supported mime_types: 'text/plain', 'text/html' + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#textsnippet + text_snippet = automl.TextSnippet(content=content, mime_type="text/plain") + payload = automl.ExamplePayload(text_snippet=text_snippet) + + response = prediction_client.predict(name=model_full_id, payload=payload) + + for annotation_payload in response.payload: + print("Text Extract Entity Types: {}".format(annotation_payload.display_name)) + print("Text Score: {}".format(annotation_payload.text_extraction.score)) + text_segment = annotation_payload.text_extraction.text_segment + print("Text Extract Entity Content: {}".format(text_segment.content)) + print("Text Start Offset: {}".format(text_segment.start_offset)) + print("Text End Offset: {}".format(text_segment.end_offset)) + # [END automl_language_entity_extraction_predict] diff --git a/automl/snippets/language_entity_extraction_predict_test.py b/automl/snippets/language_entity_extraction_predict_test.py new file mode 100644 index 00000000000..bba6e43d84f --- /dev/null +++ b/automl/snippets/language_entity_extraction_predict_test.py @@ -0,0 +1,46 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud import automl +import pytest + +import language_entity_extraction_predict + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["ENTITY_EXTRACTION_MODEL_ID"] + + +@pytest.fixture(scope="function") +def verify_model_state(): + client = automl.AutoMlClient() + model_full_id = client.model_path(PROJECT_ID, "us-central1", MODEL_ID) + + model = client.get_model(name=model_full_id) + if model.deployment_state == automl.Model.DeploymentState.UNDEPLOYED: + # Deploy model if it is not deployed + response = client.deploy_model(name=model_full_id) + response.result() + + +def test_predict(capsys, verify_model_state): + verify_model_state + text = ( + "Constitutional mutations in the WT1 gene in patients with " + "Denys-Drash syndrome." + ) + language_entity_extraction_predict.predict(PROJECT_ID, MODEL_ID, text) + out, _ = capsys.readouterr() + assert "Text Extract Entity Types: " in out diff --git a/automl/snippets/language_sentiment_analysis_create_dataset.py b/automl/snippets/language_sentiment_analysis_create_dataset.py new file mode 100644 index 00000000000..519d9a82f26 --- /dev/null +++ b/automl/snippets/language_sentiment_analysis_create_dataset.py @@ -0,0 +1,50 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_dataset(project_id, display_name): + """Create a dataset.""" + # [START automl_language_sentiment_analysis_create_dataset] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # display_name = "YOUR_DATASET_NAME" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + + # Each dataset requires a sentiment score with a defined sentiment_max + # value, for more information on TextSentimentDatasetMetadata, see: + # https://cloud.google.com/natural-language/automl/docs/prepare#sentiment-analysis + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#textsentimentdatasetmetadata + metadata = automl.TextSentimentDatasetMetadata( + sentiment_max=4 + ) # Possible max sentiment score: 1-10 + + dataset = automl.Dataset( + display_name=display_name, text_sentiment_dataset_metadata=metadata + ) + + # Create a dataset with the dataset metadata in the region. + response = client.create_dataset(parent=project_location, dataset=dataset) + + created_dataset = response.result() + + # Display the dataset information + print("Dataset name: {}".format(created_dataset.name)) + print("Dataset id: {}".format(created_dataset.name.split("/")[-1])) + # [END automl_language_sentiment_analysis_create_dataset] diff --git a/automl/snippets/language_sentiment_analysis_create_dataset_test.py b/automl/snippets/language_sentiment_analysis_create_dataset_test.py new file mode 100644 index 00000000000..1065c88099a --- /dev/null +++ b/automl/snippets/language_sentiment_analysis_create_dataset_test.py @@ -0,0 +1,37 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os + +from google.cloud import automl + +import language_sentiment_analysis_create_dataset + + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +def test_sentiment_analysis_create_dataset(capsys): + dataset_name = "test_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + language_sentiment_analysis_create_dataset.create_dataset(PROJECT_ID, dataset_name) + out, _ = capsys.readouterr() + assert "Dataset id: " in out + + # Delete the created dataset + dataset_id = out.splitlines()[1].split()[2] + client = automl.AutoMlClient() + dataset_full_id = client.dataset_path(PROJECT_ID, "us-central1", dataset_id) + response = client.delete_dataset(name=dataset_full_id) + response.result() diff --git a/automl/snippets/language_sentiment_analysis_create_model.py b/automl/snippets/language_sentiment_analysis_create_model.py new file mode 100644 index 00000000000..40262aa4f63 --- /dev/null +++ b/automl/snippets/language_sentiment_analysis_create_model.py @@ -0,0 +1,44 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_model(project_id, dataset_id, display_name): + """Create a model.""" + # [START automl_language_sentiment_analysis_create_model] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # dataset_id = "YOUR_DATASET_ID" + # display_name = "YOUR_MODEL_NAME" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + # Leave model unset to use the default base model provided by Google + metadata = automl.TextSentimentModelMetadata() + model = automl.Model( + display_name=display_name, + dataset_id=dataset_id, + text_sentiment_model_metadata=metadata, + ) + + # Create a model with the model metadata in the region. + response = client.create_model(parent=project_location, model=model) + + print("Training operation name: {}".format(response.operation.name)) + print("Training started...") + # [END automl_language_sentiment_analysis_create_model] + return response diff --git a/automl/snippets/language_sentiment_analysis_create_model_test.py b/automl/snippets/language_sentiment_analysis_create_model_test.py new file mode 100644 index 00000000000..12f49e72ed7 --- /dev/null +++ b/automl/snippets/language_sentiment_analysis_create_model_test.py @@ -0,0 +1,31 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import language_sentiment_analysis_create_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = "TST00000000000000000" + + +def test_sentiment_analysis_create_model(capsys): + try: + language_sentiment_analysis_create_model.create_model( + PROJECT_ID, DATASET_ID, "lang_sent_test_create_model" + ) + out, _ = capsys.readouterr() + assert "Dataset does not exist." in out + except Exception as e: + assert "Dataset does not exist." in e.message diff --git a/automl/snippets/language_sentiment_analysis_predict.py b/automl/snippets/language_sentiment_analysis_predict.py new file mode 100644 index 00000000000..8036d262540 --- /dev/null +++ b/automl/snippets/language_sentiment_analysis_predict.py @@ -0,0 +1,45 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def predict(project_id, model_id, content): + """Predict.""" + # [START automl_language_sentiment_analysis_predict] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + # content = "text to predict" + + prediction_client = automl.PredictionServiceClient() + + # Get the full path of the model. + model_full_id = automl.AutoMlClient.model_path(project_id, "us-central1", model_id) + + # Supported mime_types: 'text/plain', 'text/html' + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#textsnippet + text_snippet = automl.TextSnippet(content=content, mime_type="text/plain") + payload = automl.ExamplePayload(text_snippet=text_snippet) + + response = prediction_client.predict(name=model_full_id, payload=payload) + + for annotation_payload in response.payload: + print("Predicted class name: {}".format(annotation_payload.display_name)) + print( + "Predicted sentiment score: {}".format( + annotation_payload.text_sentiment.sentiment + ) + ) + # [END automl_language_sentiment_analysis_predict] diff --git a/automl/snippets/language_sentiment_analysis_predict_test.py b/automl/snippets/language_sentiment_analysis_predict_test.py new file mode 100644 index 00000000000..ee32ebc522a --- /dev/null +++ b/automl/snippets/language_sentiment_analysis_predict_test.py @@ -0,0 +1,43 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud import automl +import pytest + +import language_sentiment_analysis_predict + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["SENTIMENT_ANALYSIS_MODEL_ID"] + + +@pytest.fixture(scope="function", autouse=True) +def setup(): + # Verify the model is deployed before trying to predict + client = automl.AutoMlClient() + model_full_id = client.model_path(PROJECT_ID, "us-central1", MODEL_ID) + + model = client.get_model(name=model_full_id) + if model.deployment_state == automl.Model.DeploymentState.UNDEPLOYED: + # Deploy model if it is not deployed + response = client.deploy_model(name=model_full_id) + response.result() + + +def test_sentiment_analysis_predict(capsys): + text = "Hopefully this Claritin kicks in soon" + language_sentiment_analysis_predict.predict(PROJECT_ID, MODEL_ID, text) + out, _ = capsys.readouterr() + assert "Predicted sentiment score: " in out diff --git a/automl/snippets/language_text_classification_create_dataset.py b/automl/snippets/language_text_classification_create_dataset.py new file mode 100644 index 00000000000..943ac92d7c1 --- /dev/null +++ b/automl/snippets/language_text_classification_create_dataset.py @@ -0,0 +1,49 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_dataset(project_id, display_name): + """Create a dataset.""" + # [START automl_language_text_classification_create_dataset] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # display_name = "YOUR_DATASET_NAME" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + # Specify the classification type + # Types: + # MultiLabel: Multiple labels are allowed for one example. + # MultiClass: At most one label is allowed per example. + metadata = automl.TextClassificationDatasetMetadata( + classification_type=automl.ClassificationType.MULTICLASS + ) + dataset = automl.Dataset( + display_name=display_name, + text_classification_dataset_metadata=metadata, + ) + + # Create a dataset with the dataset metadata in the region. + response = client.create_dataset(parent=project_location, dataset=dataset) + + created_dataset = response.result() + + # Display the dataset information + print("Dataset name: {}".format(created_dataset.name)) + print("Dataset id: {}".format(created_dataset.name.split("/")[-1])) + # [END automl_language_text_classification_create_dataset] diff --git a/automl/snippets/language_text_classification_create_dataset_test.py b/automl/snippets/language_text_classification_create_dataset_test.py new file mode 100644 index 00000000000..2395e37c760 --- /dev/null +++ b/automl/snippets/language_text_classification_create_dataset_test.py @@ -0,0 +1,37 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os + +from google.cloud import automl + +import language_text_classification_create_dataset + + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +def test_text_classification_create_dataset(capsys): + dataset_name = "test_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + language_text_classification_create_dataset.create_dataset(PROJECT_ID, dataset_name) + out, _ = capsys.readouterr() + assert "Dataset id: " in out + + # Delete the created dataset + dataset_id = out.splitlines()[1].split()[2] + client = automl.AutoMlClient() + dataset_full_id = client.dataset_path(PROJECT_ID, "us-central1", dataset_id) + response = client.delete_dataset(name=dataset_full_id) + response.result() diff --git a/automl/snippets/language_text_classification_create_model.py b/automl/snippets/language_text_classification_create_model.py new file mode 100644 index 00000000000..00b5114f012 --- /dev/null +++ b/automl/snippets/language_text_classification_create_model.py @@ -0,0 +1,43 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_model(project_id, dataset_id, display_name): + """Create a model.""" + # [START automl_language_text_classification_create_model] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # dataset_id = "YOUR_DATASET_ID" + # display_name = "YOUR_MODEL_NAME" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + # Leave model unset to use the default base model provided by Google + metadata = automl.TextClassificationModelMetadata() + model = automl.Model( + display_name=display_name, + dataset_id=dataset_id, + text_classification_model_metadata=metadata, + ) + + # Create a model with the model metadata in the region. + response = client.create_model(parent=project_location, model=model) + + print("Training operation name: {}".format(response.operation.name)) + print("Training started...") + # [END automl_language_text_classification_create_model] diff --git a/automl/snippets/language_text_classification_create_model_test.py b/automl/snippets/language_text_classification_create_model_test.py new file mode 100644 index 00000000000..995fbc4e20e --- /dev/null +++ b/automl/snippets/language_text_classification_create_model_test.py @@ -0,0 +1,31 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import language_text_classification_create_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = "TCN00000000000000000000" + + +def test_text_classification_create_model(capsys): + try: + language_text_classification_create_model.create_model( + PROJECT_ID, DATASET_ID, "lang_text_test_create_model" + ) + out, _ = capsys.readouterr() + assert "Dataset does not exist." in out + except Exception as e: + assert "Dataset does not exist." in e.message diff --git a/automl/snippets/language_text_classification_predict.py b/automl/snippets/language_text_classification_predict.py new file mode 100644 index 00000000000..cfc4a6e4378 --- /dev/null +++ b/automl/snippets/language_text_classification_predict.py @@ -0,0 +1,43 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def predict(project_id, model_id, content): + """Predict.""" + # [START automl_language_text_classification_predict] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + # content = "text to predict" + + prediction_client = automl.PredictionServiceClient() + + # Get the full path of the model. + model_full_id = automl.AutoMlClient.model_path(project_id, "us-central1", model_id) + + # Supported mime_types: 'text/plain', 'text/html' + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#textsnippet + text_snippet = automl.TextSnippet(content=content, mime_type="text/plain") + payload = automl.ExamplePayload(text_snippet=text_snippet) + + response = prediction_client.predict(name=model_full_id, payload=payload) + + for annotation_payload in response.payload: + print(u"Predicted class name: {}".format(annotation_payload.display_name)) + print( + u"Predicted class score: {}".format(annotation_payload.classification.score) + ) + # [END automl_language_text_classification_predict] diff --git a/automl/snippets/language_text_classification_predict_test.py b/automl/snippets/language_text_classification_predict_test.py new file mode 100644 index 00000000000..1150d9d107e --- /dev/null +++ b/automl/snippets/language_text_classification_predict_test.py @@ -0,0 +1,43 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud import automl +import pytest + +import language_text_classification_predict + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["TEXT_CLASSIFICATION_MODEL_ID"] + + +@pytest.fixture(scope="function") +def verify_model_state(): + client = automl.AutoMlClient() + model_full_id = client.model_path(PROJECT_ID, "us-central1", MODEL_ID) + + model = client.get_model(name=model_full_id) + if model.deployment_state == automl.Model.DeploymentState.UNDEPLOYED: + # Deploy model if it is not deployed + response = client.deploy_model(name=model_full_id) + response.result() + + +def test_text_classification_predict(capsys, verify_model_state): + verify_model_state + text = "Fruit and nut flavour" + language_text_classification_predict.predict(PROJECT_ID, MODEL_ID, text) + out, _ = capsys.readouterr() + assert "Predicted class name: " in out diff --git a/automl/snippets/list_datasets.py b/automl/snippets/list_datasets.py new file mode 100644 index 00000000000..ce92355ca3c --- /dev/null +++ b/automl/snippets/list_datasets.py @@ -0,0 +1,99 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def list_datasets(project_id): + """List datasets.""" + # [START automl_language_entity_extraction_list_datasets] + # [START automl_language_sentiment_analysis_list_datasets] + # [START automl_language_text_classification_list_datasets] + # [START automl_translate_list_datasets] + # [START automl_vision_classification_list_datasets] + # [START automl_vision_object_detection_list_datasets] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + + client = automl.AutoMlClient() + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + + # List all the datasets available in the region. + request = automl.ListDatasetsRequest(parent=project_location, filter="") + response = client.list_datasets(request=request) + + print("List of datasets:") + for dataset in response: + print("Dataset name: {}".format(dataset.name)) + print("Dataset id: {}".format(dataset.name.split("/")[-1])) + print("Dataset display name: {}".format(dataset.display_name)) + print("Dataset create time: {}".format(dataset.create_time)) + # [END automl_language_sentiment_analysis_list_datasets] + # [END automl_language_text_classification_list_datasets] + # [END automl_translate_list_datasets] + # [END automl_vision_classification_list_datasets] + # [END automl_vision_object_detection_list_datasets] + print( + "Text extraction dataset metadata: {}".format( + dataset.text_extraction_dataset_metadata + ) + ) + # [END automl_language_entity_extraction_list_datasets] + + # [START automl_language_sentiment_analysis_list_datasets] + print( + "Text sentiment dataset metadata: {}".format( + dataset.text_sentiment_dataset_metadata + ) + ) + # [END automl_language_sentiment_analysis_list_datasets] + + # [START automl_language_text_classification_list_datasets] + print( + "Text classification dataset metadata: {}".format( + dataset.text_classification_dataset_metadata + ) + ) + # [END automl_language_text_classification_list_datasets] + + # [START automl_translate_list_datasets] + print("Translation dataset metadata:") + print( + "\tsource_language_code: {}".format( + dataset.translation_dataset_metadata.source_language_code + ) + ) + print( + "\ttarget_language_code: {}".format( + dataset.translation_dataset_metadata.target_language_code + ) + ) + # [END automl_translate_list_datasets] + + # [START automl_vision_classification_list_datasets] + print( + "Image classification dataset metadata: {}".format( + dataset.image_classification_dataset_metadata + ) + ) + # [END automl_vision_classification_list_datasets] + + # [START automl_vision_object_detection_list_datasets] + print( + "Image object detection dataset metadata: {}".format( + dataset.image_object_detection_dataset_metadata + ) + ) + # [END automl_vision_object_detection_list_datasets] diff --git a/automl/snippets/list_datasets_test.py b/automl/snippets/list_datasets_test.py new file mode 100644 index 00000000000..7057af815d1 --- /dev/null +++ b/automl/snippets/list_datasets_test.py @@ -0,0 +1,27 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import list_datasets + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = os.environ["ENTITY_EXTRACTION_DATASET_ID"] + + +def test_list_dataset(capsys): + # list datasets + list_datasets.list_datasets(PROJECT_ID) + out, _ = capsys.readouterr() + assert "Dataset id: {}".format(DATASET_ID) in out diff --git a/automl/snippets/list_model_evaluations.py b/automl/snippets/list_model_evaluations.py new file mode 100644 index 00000000000..8037553c3cc --- /dev/null +++ b/automl/snippets/list_model_evaluations.py @@ -0,0 +1,84 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def list_model_evaluations(project_id, model_id): + """List model evaluations.""" + # [START automl_language_entity_extraction_list_model_evaluations] + # [START automl_language_sentiment_analysis_list_model_evaluations] + # [START automl_language_text_classification_list_model_evaluations] + # [START automl_translate_list_model_evaluations] + # [START automl_vision_classification_list_model_evaluations] + # [START automl_vision_object_detection_list_model_evaluations] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + + client = automl.AutoMlClient() + # Get the full path of the model. + model_full_id = client.model_path(project_id, "us-central1", model_id) + + print("List of model evaluations:") + for evaluation in client.list_model_evaluations(parent=model_full_id, filter=""): + print("Model evaluation name: {}".format(evaluation.name)) + print("Model annotation spec id: {}".format(evaluation.annotation_spec_id)) + print("Create Time: {}".format(evaluation.create_time)) + print("Evaluation example count: {}".format(evaluation.evaluated_example_count)) + # [END automl_language_sentiment_analysis_list_model_evaluations] + # [END automl_language_text_classification_list_model_evaluations] + # [END automl_translate_list_model_evaluations] + # [END automl_vision_classification_list_model_evaluations] + # [END automl_vision_object_detection_list_model_evaluations] + print( + "Entity extraction model evaluation metrics: {}".format( + evaluation.text_extraction_evaluation_metrics + ) + ) + # [END automl_language_entity_extraction_list_model_evaluations] + + # [START automl_language_sentiment_analysis_list_model_evaluations] + print( + "Sentiment analysis model evaluation metrics: {}".format( + evaluation.text_sentiment_evaluation_metrics + ) + ) + # [END automl_language_sentiment_analysis_list_model_evaluations] + + # [START automl_language_text_classification_list_model_evaluations] + # [START automl_vision_classification_list_model_evaluations] + print( + "Classification model evaluation metrics: {}".format( + evaluation.classification_evaluation_metrics + ) + ) + # [END automl_language_text_classification_list_model_evaluations] + # [END automl_vision_classification_list_model_evaluations] + + # [START automl_translate_list_model_evaluations] + print( + "Translation model evaluation metrics: {}".format( + evaluation.translation_evaluation_metrics + ) + ) + # [END automl_translate_list_model_evaluations] + + # [START automl_vision_object_detection_list_model_evaluations] + print( + "Object detection model evaluation metrics: {}\n\n".format( + evaluation.image_object_detection_evaluation_metrics + ) + ) + # [END automl_vision_object_detection_list_model_evaluations] diff --git a/automl/snippets/list_model_evaluations_test.py b/automl/snippets/list_model_evaluations_test.py new file mode 100644 index 00000000000..9d8cbc5989d --- /dev/null +++ b/automl/snippets/list_model_evaluations_test.py @@ -0,0 +1,27 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import list_model_evaluations + + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["ENTITY_EXTRACTION_MODEL_ID"] + + +def test_list_model_evaluations(capsys): + list_model_evaluations.list_model_evaluations(PROJECT_ID, MODEL_ID) + out, _ = capsys.readouterr() + assert "Model evaluation name: " in out diff --git a/automl/snippets/list_models.py b/automl/snippets/list_models.py new file mode 100644 index 00000000000..80913105af1 --- /dev/null +++ b/automl/snippets/list_models.py @@ -0,0 +1,44 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def list_models(project_id): + """List models.""" + # [START automl_list_models] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + + client = automl.AutoMlClient() + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + + request = automl.ListModelsRequest(parent=project_location, filter="") + response = client.list_models(request=request) + + print("List of models:") + for model in response: + # Display the model information. + if model.deployment_state == automl.Model.DeploymentState.DEPLOYED: + deployment_state = "deployed" + else: + deployment_state = "undeployed" + + print("Model name: {}".format(model.name)) + print("Model id: {}".format(model.name.split("/")[-1])) + print("Model display name: {}".format(model.display_name)) + print("Model create time: {}".format(model.create_time)) + print("Model deployment state: {}".format(deployment_state)) + # [END automl_list_models] diff --git a/automl/snippets/list_models_test.py b/automl/snippets/list_models_test.py new file mode 100644 index 00000000000..93f79d580e7 --- /dev/null +++ b/automl/snippets/list_models_test.py @@ -0,0 +1,25 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import list_models + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +def test_list_models(capsys): + list_models.list_models(PROJECT_ID) + out, _ = capsys.readouterr() + assert "Model id: " in out diff --git a/automl/snippets/list_operation_status.py b/automl/snippets/list_operation_status.py new file mode 100644 index 00000000000..679ff66e539 --- /dev/null +++ b/automl/snippets/list_operation_status.py @@ -0,0 +1,37 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def list_operation_status(project_id): + """List operation status.""" + # [START automl_list_operation_status] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + + client = automl.AutoMlClient() + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + # List all the operations names available in the region. + response = client._transport.operations_client.list_operations( + name=project_location, filter_="", timeout=5 + ) + + print("List of operations:") + for operation in response: + print("Name: {}".format(operation.name)) + print("Operation details:") + print(operation) + # [END automl_list_operation_status] diff --git a/automl/snippets/list_operation_status_test.py b/automl/snippets/list_operation_status_test.py new file mode 100644 index 00000000000..aaeccaaf1ab --- /dev/null +++ b/automl/snippets/list_operation_status_test.py @@ -0,0 +1,35 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import backoff +from google.api_core.exceptions import InternalServerError +import pytest + +import list_operation_status + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +@pytest.mark.slow +def test_list_operation_status(capsys): + # We saw 500 InternalServerError. Now we just retry few times. + @backoff.on_exception(backoff.expo, InternalServerError, max_time=120) + def run_sample(): + list_operation_status.list_operation_status(PROJECT_ID) + + run_sample() + out, _ = capsys.readouterr() + assert "Operation details" in out diff --git a/automl/snippets/requirements-test.txt b/automl/snippets/requirements-test.txt new file mode 100644 index 00000000000..b90fc387d01 --- /dev/null +++ b/automl/snippets/requirements-test.txt @@ -0,0 +1,2 @@ +backoff==2.2.1 +pytest==7.2.0 diff --git a/automl/snippets/requirements.txt b/automl/snippets/requirements.txt new file mode 100644 index 00000000000..8526082bd8f --- /dev/null +++ b/automl/snippets/requirements.txt @@ -0,0 +1,3 @@ +google-cloud-translate==3.8.4 +google-cloud-storage==2.5.0 +google-cloud-automl==2.8.3 diff --git a/automl/snippets/resources/input.txt b/automl/snippets/resources/input.txt new file mode 100644 index 00000000000..ac25dac422b --- /dev/null +++ b/automl/snippets/resources/input.txt @@ -0,0 +1,14 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +Tell me how this ends \ No newline at end of file diff --git a/automl/snippets/resources/salad.jpg b/automl/snippets/resources/salad.jpg new file mode 100644 index 00000000000..a7f960b5030 Binary files /dev/null and b/automl/snippets/resources/salad.jpg differ diff --git a/automl/snippets/resources/test.png b/automl/snippets/resources/test.png new file mode 100644 index 00000000000..653342a46e5 Binary files /dev/null and b/automl/snippets/resources/test.png differ diff --git a/automl/snippets/translate_create_dataset.py b/automl/snippets/translate_create_dataset.py new file mode 100644 index 00000000000..b82b9b0370f --- /dev/null +++ b/automl/snippets/translate_create_dataset.py @@ -0,0 +1,47 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_dataset(project_id, display_name): + """Create a dataset.""" + # [START automl_translate_create_dataset] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # display_name = "YOUR_DATASET_NAME" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + # For a list of supported languages, see: + # https://cloud.google.com/translate/automl/docs/languages + dataset_metadata = automl.TranslationDatasetMetadata( + source_language_code="en", target_language_code="ja" + ) + dataset = automl.Dataset( + display_name=display_name, + translation_dataset_metadata=dataset_metadata, + ) + + # Create a dataset with the dataset metadata in the region. + response = client.create_dataset(parent=project_location, dataset=dataset) + + created_dataset = response.result() + + # Display the dataset information + print("Dataset name: {}".format(created_dataset.name)) + print("Dataset id: {}".format(created_dataset.name.split("/")[-1])) + # [END automl_translate_create_dataset] diff --git a/automl/snippets/translate_create_dataset_test.py b/automl/snippets/translate_create_dataset_test.py new file mode 100644 index 00000000000..d25f0f8e55f --- /dev/null +++ b/automl/snippets/translate_create_dataset_test.py @@ -0,0 +1,38 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os + +from google.cloud import automl + +import translate_create_dataset + + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +def test_translate_create_dataset(capsys): + # create dataset + dataset_name = "test_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + translate_create_dataset.create_dataset(PROJECT_ID, dataset_name) + out, _ = capsys.readouterr() + assert "Dataset id: " in out + + # Delete the created dataset + dataset_id = out.splitlines()[1].split()[2] + client = automl.AutoMlClient() + dataset_full_id = client.dataset_path(PROJECT_ID, "us-central1", dataset_id) + response = client.delete_dataset(name=dataset_full_id) + response.result() diff --git a/automl/snippets/translate_create_model.py b/automl/snippets/translate_create_model.py new file mode 100644 index 00000000000..fecdb0220ab --- /dev/null +++ b/automl/snippets/translate_create_model.py @@ -0,0 +1,42 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_model(project_id, dataset_id, display_name): + """Create a model.""" + # [START automl_translate_create_model] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # dataset_id = "YOUR_DATASET_ID" + # display_name = "YOUR_MODEL_NAME" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + translation_model_metadata = automl.TranslationModelMetadata() + model = automl.Model( + display_name=display_name, + dataset_id=dataset_id, + translation_model_metadata=translation_model_metadata, + ) + + # Create a model with the model metadata in the region. + response = client.create_model(parent=project_location, model=model) + + print("Training operation name: {}".format(response.operation.name)) + print("Training started...") + # [END automl_translate_create_model] diff --git a/automl/snippets/translate_create_model_test.py b/automl/snippets/translate_create_model_test.py new file mode 100644 index 00000000000..933a45d2641 --- /dev/null +++ b/automl/snippets/translate_create_model_test.py @@ -0,0 +1,35 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import translate_create_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = "TRL00000000000000000" + + +def test_translate_create_model(capsys): + try: + translate_create_model.create_model( + PROJECT_ID, DATASET_ID, "translate_test_create_model" + ) + out, _ = capsys.readouterr() + # After setting DATASET_ID, change line below to + # assert "Training started..." in out + assert "Dataset does not exist." in out + except Exception as e: + # After setting DATASET_ID, change line below to + # assert "Training started..." in e.message + assert "Dataset does not exist." in e.message diff --git a/automl/snippets/translate_predict.py b/automl/snippets/translate_predict.py new file mode 100644 index 00000000000..9b93f28485e --- /dev/null +++ b/automl/snippets/translate_predict.py @@ -0,0 +1,43 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def predict(project_id, model_id, file_path): + """Predict.""" + # [START automl_translate_predict] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + # file_path = "path_to_local_file.txt" + + prediction_client = automl.PredictionServiceClient() + + # Get the full path of the model. + model_full_id = automl.AutoMlClient.model_path(project_id, "us-central1", model_id) + + # Read the file content for translation. + with open(file_path, "rb") as content_file: + content = content_file.read() + content.decode("utf-8") + + text_snippet = automl.TextSnippet(content=content) + payload = automl.ExamplePayload(text_snippet=text_snippet) + + response = prediction_client.predict(name=model_full_id, payload=payload) + translated_content = response.payload[0].translation.translated_content + + print(u"Translated content: {}".format(translated_content.content)) + # [END automl_translate_predict] diff --git a/automl/snippets/translate_predict_test.py b/automl/snippets/translate_predict_test.py new file mode 100644 index 00000000000..4f0c45a1807 --- /dev/null +++ b/automl/snippets/translate_predict_test.py @@ -0,0 +1,42 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud import automl +import pytest + +import translate_predict + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["TRANSLATION_MODEL_ID"] + + +@pytest.fixture(scope="function", autouse=True) +def setup(): + # Verify the model is deployed before trying to predict + client = automl.AutoMlClient() + model_full_id = client.model_path(PROJECT_ID, "us-central1", MODEL_ID) + + model = client.get_model(name=model_full_id) + if model.deployment_state == automl.Model.DeploymentState.UNDEPLOYED: + # Deploy model if it is not deployed + response = client.deploy_model(name=model_full_id) + response.result() + + +def test_translate_predict(capsys): + translate_predict.predict(PROJECT_ID, MODEL_ID, "resources/input.txt") + out, _ = capsys.readouterr() + assert "Translated content: " in out diff --git a/automl/snippets/undeploy_model.py b/automl/snippets/undeploy_model.py new file mode 100644 index 00000000000..25b5cdb7c50 --- /dev/null +++ b/automl/snippets/undeploy_model.py @@ -0,0 +1,31 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def undeploy_model(project_id, model_id): + """Undeploy a model.""" + # [START automl_undeploy_model] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + + client = automl.AutoMlClient() + # Get the full path of the model. + model_full_id = client.model_path(project_id, "us-central1", model_id) + response = client.undeploy_model(name=model_full_id) + + print("Model undeployment finished. {}".format(response.result())) + # [END automl_undeploy_model] diff --git a/automl/snippets/undeploy_model_test.py b/automl/snippets/undeploy_model_test.py new file mode 100644 index 00000000000..49e9b1305e3 --- /dev/null +++ b/automl/snippets/undeploy_model_test.py @@ -0,0 +1,35 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytest + +import undeploy_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = "TRL0000000000000000000" + + +@pytest.mark.slow +def test_undeploy_model(capsys): + # As model undeployment can take a long time, instead try to deploy a + # nonexistent model and confirm that the model was not found, but other + # elements of the request were valid. + try: + undeploy_model.undeploy_model(PROJECT_ID, MODEL_ID) + out, _ = capsys.readouterr() + assert "The model does not exist" in out + except Exception as e: + assert "The model does not exist" in e.message diff --git a/automl/snippets/vision_classification_create_dataset.py b/automl/snippets/vision_classification_create_dataset.py new file mode 100644 index 00000000000..67595c8238c --- /dev/null +++ b/automl/snippets/vision_classification_create_dataset.py @@ -0,0 +1,50 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_dataset(project_id, display_name): + """Create a dataset.""" + # [START automl_vision_classification_create_dataset] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # display_name = "your_datasets_display_name" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + # Specify the classification type + # Types: + # MultiLabel: Multiple labels are allowed for one example. + # MultiClass: At most one label is allowed per example. + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#classificationtype + metadata = automl.ImageClassificationDatasetMetadata( + classification_type=automl.ClassificationType.MULTILABEL + ) + dataset = automl.Dataset( + display_name=display_name, + image_classification_dataset_metadata=metadata, + ) + + # Create a dataset with the dataset metadata in the region. + response = client.create_dataset(parent=project_location, dataset=dataset, timeout=300) + + created_dataset = response.result() + + # Display the dataset information + print("Dataset name: {}".format(created_dataset.name)) + print("Dataset id: {}".format(created_dataset.name.split("/")[-1])) + # [END automl_vision_classification_create_dataset] diff --git a/automl/snippets/vision_classification_create_dataset_test.py b/automl/snippets/vision_classification_create_dataset_test.py new file mode 100644 index 00000000000..7b86f42e4c1 --- /dev/null +++ b/automl/snippets/vision_classification_create_dataset_test.py @@ -0,0 +1,40 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os + +from google.cloud import automl +import pytest + +import vision_classification_create_dataset + + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +@pytest.mark.slow +def test_vision_classification_create_dataset(capsys): + # create dataset + dataset_name = "test_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + vision_classification_create_dataset.create_dataset(PROJECT_ID, dataset_name) + out, _ = capsys.readouterr() + assert "Dataset id: " in out + + # Delete the created dataset + dataset_id = out.splitlines()[1].split()[2] + client = automl.AutoMlClient() + dataset_full_id = client.dataset_path(PROJECT_ID, "us-central1", dataset_id) + response = client.delete_dataset(name=dataset_full_id) + response.result() diff --git a/automl/snippets/vision_classification_create_model.py b/automl/snippets/vision_classification_create_model.py new file mode 100644 index 00000000000..06cf770675e --- /dev/null +++ b/automl/snippets/vision_classification_create_model.py @@ -0,0 +1,49 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_model(project_id, dataset_id, display_name): + """Create a model.""" + # [START automl_vision_classification_create_model] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # dataset_id = "YOUR_DATASET_ID" + # display_name = "your_models_display_name" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + # Leave model unset to use the default base model provided by Google + # train_budget_milli_node_hours: The actual train_cost will be equal or + # less than this value. + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#imageclassificationmodelmetadata + metadata = automl.ImageClassificationModelMetadata( + train_budget_milli_node_hours=24000 + ) + model = automl.Model( + display_name=display_name, + dataset_id=dataset_id, + image_classification_model_metadata=metadata, + ) + + # Create a model with the model metadata in the region. + response = client.create_model(parent=project_location, model=model) + + print("Training operation name: {}".format(response.operation.name)) + print("Training started...") + # [END automl_vision_classification_create_model] + return response diff --git a/automl/snippets/vision_classification_create_model_test.py b/automl/snippets/vision_classification_create_model_test.py new file mode 100644 index 00000000000..46bec0463e8 --- /dev/null +++ b/automl/snippets/vision_classification_create_model_test.py @@ -0,0 +1,31 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import vision_classification_create_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = "ICN000000000000000000" + + +def test_vision_classification_create_model(capsys): + try: + vision_classification_create_model.create_model( + PROJECT_ID, DATASET_ID, "classification_test_create_model" + ) + out, _ = capsys.readouterr() + assert "Dataset does not exist." in out + except Exception as e: + assert "Dataset does not exist." in e.message diff --git a/automl/snippets/vision_classification_deploy_model_node_count.py b/automl/snippets/vision_classification_deploy_model_node_count.py new file mode 100644 index 00000000000..3884477d672 --- /dev/null +++ b/automl/snippets/vision_classification_deploy_model_node_count.py @@ -0,0 +1,39 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def deploy_model(project_id, model_id): + """Deploy a model with a specified node count.""" + # [START automl_vision_classification_deploy_model_node_count] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + + client = automl.AutoMlClient() + # Get the full path of the model. + model_full_id = client.model_path(project_id, "us-central1", model_id) + + # node count determines the number of nodes to deploy the model on. + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#imageclassificationmodeldeploymentmetadata + metadata = automl.ImageClassificationModelDeploymentMetadata(node_count=2) + + request = automl.DeployModelRequest( + name=model_full_id, image_classification_model_deployment_metadata=metadata + ) + response = client.deploy_model(request=request) + + print("Model deployment finished. {}".format(response.result())) + # [END automl_vision_classification_deploy_model_node_count] diff --git a/automl/snippets/vision_classification_deploy_model_node_count_test.py b/automl/snippets/vision_classification_deploy_model_node_count_test.py new file mode 100644 index 00000000000..c565b58de05 --- /dev/null +++ b/automl/snippets/vision_classification_deploy_model_node_count_test.py @@ -0,0 +1,35 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytest + +import vision_classification_deploy_model_node_count + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = "ICN0000000000000000000" + + +@pytest.mark.slow +def test_classification_deploy_model_with_node_count(capsys): + # As model deployment can take a long time, instead try to deploy a + # nonexistent model and confirm that the model was not found, but other + # elements of the request were valid. + try: + vision_classification_deploy_model_node_count.deploy_model(PROJECT_ID, MODEL_ID) + out, _ = capsys.readouterr() + assert "The model does not exist" in out + except Exception as e: + assert "The model does not exist" in e.message diff --git a/automl/snippets/vision_classification_predict.py b/automl/snippets/vision_classification_predict.py new file mode 100644 index 00000000000..355de0bc08a --- /dev/null +++ b/automl/snippets/vision_classification_predict.py @@ -0,0 +1,50 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def predict(project_id, model_id, file_path): + """Predict.""" + # [START automl_vision_classification_predict] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + # file_path = "path_to_local_file.jpg" + + prediction_client = automl.PredictionServiceClient() + + # Get the full path of the model. + model_full_id = automl.AutoMlClient.model_path(project_id, "us-central1", model_id) + + # Read the file. + with open(file_path, "rb") as content_file: + content = content_file.read() + + image = automl.Image(image_bytes=content) + payload = automl.ExamplePayload(image=image) + + # params is additional domain-specific parameters. + # score_threshold is used to filter the result + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#predictrequest + params = {"score_threshold": "0.8"} + + request = automl.PredictRequest(name=model_full_id, payload=payload, params=params) + response = prediction_client.predict(request=request) + + print("Prediction results:") + for result in response.payload: + print("Predicted class name: {}".format(result.display_name)) + print("Predicted class score: {}".format(result.classification.score)) + # [END automl_vision_classification_predict] diff --git a/automl/snippets/vision_classification_predict_test.py b/automl/snippets/vision_classification_predict_test.py new file mode 100644 index 00000000000..71af7433c9b --- /dev/null +++ b/automl/snippets/vision_classification_predict_test.py @@ -0,0 +1,43 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud import automl +import pytest + +import vision_classification_predict + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["VISION_CLASSIFICATION_MODEL_ID"] + + +@pytest.fixture(scope="function", autouse=True) +def setup(): + # Verify the model is deployed before tyring to predict + client = automl.AutoMlClient() + model_full_id = client.model_path(PROJECT_ID, "us-central1", MODEL_ID) + + model = client.get_model(name=model_full_id) + if model.deployment_state == automl.Model.DeploymentState.UNDEPLOYED: + # Deploy model if it is not deployed + response = client.deploy_model(name=model_full_id) + response.result() + + +def test_vision_classification_predict(capsys): + file_path = "resources/test.png" + vision_classification_predict.predict(PROJECT_ID, MODEL_ID, file_path) + out, _ = capsys.readouterr() + assert "Predicted class name:" in out diff --git a/automl/snippets/vision_object_detection_create_dataset.py b/automl/snippets/vision_object_detection_create_dataset.py new file mode 100644 index 00000000000..29822e26ed5 --- /dev/null +++ b/automl/snippets/vision_object_detection_create_dataset.py @@ -0,0 +1,43 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_dataset(project_id, display_name): + """Create a dataset.""" + # [START automl_vision_object_detection_create_dataset] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # display_name = "your_datasets_display_name" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + metadata = automl.ImageObjectDetectionDatasetMetadata() + dataset = automl.Dataset( + display_name=display_name, + image_object_detection_dataset_metadata=metadata, + ) + + # Create a dataset with the dataset metadata in the region. + response = client.create_dataset(parent=project_location, dataset=dataset) + + created_dataset = response.result() + + # Display the dataset information + print("Dataset name: {}".format(created_dataset.name)) + print("Dataset id: {}".format(created_dataset.name.split("/")[-1])) + # [END automl_vision_object_detection_create_dataset] diff --git a/automl/snippets/vision_object_detection_create_dataset_test.py b/automl/snippets/vision_object_detection_create_dataset_test.py new file mode 100644 index 00000000000..97cff120b6d --- /dev/null +++ b/automl/snippets/vision_object_detection_create_dataset_test.py @@ -0,0 +1,40 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import datetime +import os + +from google.cloud import automl +import pytest + +import vision_object_detection_create_dataset + + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] + + +@pytest.mark.slow +def test_vision_object_detection_create_dataset(capsys): + # create dataset + dataset_name = "test_" + datetime.datetime.now().strftime("%Y%m%d%H%M%S") + vision_object_detection_create_dataset.create_dataset(PROJECT_ID, dataset_name) + out, _ = capsys.readouterr() + assert "Dataset id: " in out + + # Delete the created dataset + dataset_id = out.splitlines()[1].split()[2] + client = automl.AutoMlClient() + dataset_full_id = client.dataset_path(PROJECT_ID, "us-central1", dataset_id) + response = client.delete_dataset(name=dataset_full_id) + response.result() diff --git a/automl/snippets/vision_object_detection_create_model.py b/automl/snippets/vision_object_detection_create_model.py new file mode 100644 index 00000000000..d00c0a669b8 --- /dev/null +++ b/automl/snippets/vision_object_detection_create_model.py @@ -0,0 +1,49 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_model(project_id, dataset_id, display_name): + """Create a model.""" + # [START automl_vision_object_detection_create_model] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # dataset_id = "YOUR_DATASET_ID" + # display_name = "your_models_display_name" + + client = automl.AutoMlClient() + + # A resource that represents Google Cloud Platform location. + project_location = f"projects/{project_id}/locations/us-central1" + # Leave model unset to use the default base model provided by Google + # train_budget_milli_node_hours: The actual train_cost will be equal or + # less than this value. + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#imageobjectdetectionmodelmetadata + metadata = automl.ImageObjectDetectionModelMetadata( + train_budget_milli_node_hours=24000 + ) + model = automl.Model( + display_name=display_name, + dataset_id=dataset_id, + image_object_detection_model_metadata=metadata, + ) + + # Create a model with the model metadata in the region. + response = client.create_model(parent=project_location, model=model) + + print("Training operation name: {}".format(response.operation.name)) + print("Training started...") + # [END automl_vision_object_detection_create_model] + return response diff --git a/automl/snippets/vision_object_detection_create_model_test.py b/automl/snippets/vision_object_detection_create_model_test.py new file mode 100644 index 00000000000..07ff227ae55 --- /dev/null +++ b/automl/snippets/vision_object_detection_create_model_test.py @@ -0,0 +1,31 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import vision_object_detection_create_model + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +DATASET_ID = "IOD0000000000000000" + + +def test_vision_object_detection_create_model(capsys): + try: + vision_object_detection_create_model.create_model( + PROJECT_ID, DATASET_ID, "object_test_create_model" + ) + out, _ = capsys.readouterr() + assert "Dataset does not exist." in out + except Exception as e: + assert "Dataset does not exist." in e.message diff --git a/automl/snippets/vision_object_detection_deploy_model_node_count.py b/automl/snippets/vision_object_detection_deploy_model_node_count.py new file mode 100644 index 00000000000..cc65941b102 --- /dev/null +++ b/automl/snippets/vision_object_detection_deploy_model_node_count.py @@ -0,0 +1,40 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def deploy_model(project_id, model_id): + """Deploy a model with a specified node count.""" + # [START automl_vision_object_detection_deploy_model_node_count] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + + client = automl.AutoMlClient() + # Get the full path of the model. + model_full_id = client.model_path(project_id, "us-central1", model_id) + + # node count determines the number of nodes to deploy the model on. + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#imageobjectdetectionmodeldeploymentmetadata + metadata = automl.ImageObjectDetectionModelDeploymentMetadata(node_count=2) + + request = automl.DeployModelRequest( + name=model_full_id, + image_object_detection_model_deployment_metadata=metadata, + ) + response = client.deploy_model(request=request) + + print("Model deployment finished. {}".format(response.result())) + # [END automl_vision_object_detection_deploy_model_node_count] diff --git a/automl/snippets/vision_object_detection_deploy_model_node_count_test.py b/automl/snippets/vision_object_detection_deploy_model_node_count_test.py new file mode 100644 index 00000000000..309b2525982 --- /dev/null +++ b/automl/snippets/vision_object_detection_deploy_model_node_count_test.py @@ -0,0 +1,37 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import pytest + +import vision_object_detection_deploy_model_node_count + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = "0000000000000000000000" + + +@pytest.mark.slow +def test_object_detection_deploy_model_with_node_count(capsys): + # As model deployment can take a long time, instead try to deploy a + # nonexistent model and confirm that the model was not found, but other + # elements of the request were valid. + try: + vision_object_detection_deploy_model_node_count.deploy_model( + PROJECT_ID, MODEL_ID + ) + out, _ = capsys.readouterr() + assert "The model does not exist" in out + except Exception as e: + assert "The model does not exist" in e.message diff --git a/automl/snippets/vision_object_detection_predict.py b/automl/snippets/vision_object_detection_predict.py new file mode 100644 index 00000000000..51ed0ac029f --- /dev/null +++ b/automl/snippets/vision_object_detection_predict.py @@ -0,0 +1,54 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def predict(project_id, model_id, file_path): + """Predict.""" + # [START automl_vision_object_detection_predict] + from google.cloud import automl + + # TODO(developer): Uncomment and set the following variables + # project_id = "YOUR_PROJECT_ID" + # model_id = "YOUR_MODEL_ID" + # file_path = "path_to_local_file.jpg" + + prediction_client = automl.PredictionServiceClient() + + # Get the full path of the model. + model_full_id = automl.AutoMlClient.model_path(project_id, "us-central1", model_id) + + # Read the file. + with open(file_path, "rb") as content_file: + content = content_file.read() + + image = automl.Image(image_bytes=content) + payload = automl.ExamplePayload(image=image) + + # params is additional domain-specific parameters. + # score_threshold is used to filter the result + # https://cloud.google.com/automl/docs/reference/rpc/google.cloud.automl.v1#predictrequest + params = {"score_threshold": "0.8"} + + request = automl.PredictRequest(name=model_full_id, payload=payload, params=params) + + response = prediction_client.predict(request=request) + print("Prediction results:") + for result in response.payload: + print("Predicted class name: {}".format(result.display_name)) + print("Predicted class score: {}".format(result.image_object_detection.score)) + bounding_box = result.image_object_detection.bounding_box + print("Normalized Vertices:") + for vertex in bounding_box.normalized_vertices: + print("\tX: {}, Y: {}".format(vertex.x, vertex.y)) + # [END automl_vision_object_detection_predict] diff --git a/automl/snippets/vision_object_detection_predict_test.py b/automl/snippets/vision_object_detection_predict_test.py new file mode 100644 index 00000000000..6ba9af363a5 --- /dev/null +++ b/automl/snippets/vision_object_detection_predict_test.py @@ -0,0 +1,50 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import backoff +from google.api_core.exceptions import DeadlineExceeded +from google.cloud import automl +import pytest + +import vision_object_detection_predict + +PROJECT_ID = os.environ["AUTOML_PROJECT_ID"] +MODEL_ID = os.environ["OBJECT_DETECTION_MODEL_ID"] + + +@pytest.fixture(scope="function") +def verify_model_state(): + client = automl.AutoMlClient() + model_full_id = client.model_path(PROJECT_ID, "us-central1", MODEL_ID) + + model = client.get_model(name=model_full_id) + if model.deployment_state == automl.Model.DeploymentState.UNDEPLOYED: + # Deploy model if it is not deployed + response = client.deploy_model(name=model_full_id) + response.result(600) # 10 minutes + + +def test_vision_object_detection_predict(capsys, verify_model_state): + file_path = "resources/salad.jpg" + + # Retry the sample upon DeadlineExceeded, with a hard deadline of 5 mins. + @backoff.on_exception(backoff.expo, DeadlineExceeded, max_time=300) + def run_sample(): + vision_object_detection_predict.predict(PROJECT_ID, MODEL_ID, file_path) + + run_sample() + out, _ = capsys.readouterr() + assert "Predicted class name:" in out diff --git a/automl/tables/automl_tables_dataset.py b/automl/tables/automl_tables_dataset.py new file mode 100644 index 00000000000..a5d379457db --- /dev/null +++ b/automl/tables/automl_tables_dataset.py @@ -0,0 +1,300 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This application demonstrates how to perform basic operations on dataset +with the Google AutoML Tables API. + +For more information, the documentation at +https://cloud.google.com/automl-tables/docs. +""" + +import argparse +import os + + +def create_dataset(project_id, compute_region, dataset_display_name): + """Create a dataset.""" + # [START automl_tables_create_dataset] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # dataset_display_name = 'DATASET_DISPLAY_NAME_HERE' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # Create a dataset with the given display name + dataset = client.create_dataset(dataset_display_name) + + # Display the dataset information. + print("Dataset name: {}".format(dataset.name)) + print("Dataset id: {}".format(dataset.name.split("/")[-1])) + print("Dataset display name: {}".format(dataset.display_name)) + print("Dataset metadata:") + print("\t{}".format(dataset.tables_dataset_metadata)) + print("Dataset example count: {}".format(dataset.example_count)) + print("Dataset create time: {}".format(dataset.create_time)) + + # [END automl_tables_create_dataset] + + return dataset + + +def list_datasets(project_id, compute_region, filter=None): + """List all datasets.""" + result = [] + # [START automl_tables_list_datasets] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # filter = 'filter expression here' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # List all the datasets available in the region by applying filter. + response = client.list_datasets(filter=filter) + + print("List of datasets:") + for dataset in response: + # Display the dataset information. + print("Dataset name: {}".format(dataset.name)) + print("Dataset id: {}".format(dataset.name.split("/")[-1])) + print("Dataset display name: {}".format(dataset.display_name)) + metadata = dataset.tables_dataset_metadata + print( + "Dataset primary table spec id: {}".format( + metadata.primary_table_spec_id + ) + ) + print( + "Dataset target column spec id: {}".format( + metadata.target_column_spec_id + ) + ) + print( + "Dataset target column spec id: {}".format( + metadata.target_column_spec_id + ) + ) + print( + "Dataset weight column spec id: {}".format( + metadata.weight_column_spec_id + ) + ) + print( + "Dataset ml use column spec id: {}".format( + metadata.ml_use_column_spec_id + ) + ) + print("Dataset example count: {}".format(dataset.example_count)) + print("Dataset create time: {}".format(dataset.create_time)) + print("\n") + + # [END automl_tables_list_datasets] + result.append(dataset) + + return result + + +def get_dataset(project_id, compute_region, dataset_display_name): + """Get the dataset.""" + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # dataset_display_name = 'DATASET_DISPLAY_NAME_HERE' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # Get complete detail of the dataset. + dataset = client.get_dataset(dataset_display_name=dataset_display_name) + + # Display the dataset information. + print("Dataset name: {}".format(dataset.name)) + print("Dataset id: {}".format(dataset.name.split("/")[-1])) + print("Dataset display name: {}".format(dataset.display_name)) + print("Dataset metadata:") + print("\t{}".format(dataset.tables_dataset_metadata)) + print("Dataset example count: {}".format(dataset.example_count)) + print("Dataset create time: {}".format(dataset.create_time)) + + return dataset + + +def import_data(project_id, compute_region, dataset_display_name, path): + """Import structured data.""" + # [START automl_tables_import_data] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # dataset_display_name = 'DATASET_DISPLAY_NAME' + # path = 'gs://path/to/file.csv' or 'bq://project_id.dataset.table_id' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + response = None + if path.startswith("bq"): + response = client.import_data( + dataset_display_name=dataset_display_name, bigquery_input_uri=path + ) + else: + # Get the multiple Google Cloud Storage URIs. + input_uris = path.split(",") + response = client.import_data( + dataset_display_name=dataset_display_name, + gcs_input_uris=input_uris, + ) + + print("Processing import...") + # synchronous check of operation status. + print("Data imported. {}".format(response.result())) + + # [END automl_tables_import_data] + + +def update_dataset( + project_id, + compute_region, + dataset_display_name, + target_column_spec_name=None, + weight_column_spec_name=None, + test_train_column_spec_name=None, +): + """Update dataset.""" + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # dataset_display_name = 'DATASET_DISPLAY_NAME_HERE' + # target_column_spec_name = 'TARGET_COLUMN_SPEC_NAME_HERE' or None + # weight_column_spec_name = 'WEIGHT_COLUMN_SPEC_NAME_HERE' or None + # test_train_column_spec_name = 'TEST_TRAIN_COLUMN_SPEC_NAME_HERE' or None + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + if target_column_spec_name is not None: + response = client.set_target_column( + dataset_display_name=dataset_display_name, + column_spec_display_name=target_column_spec_name, + ) + print("Target column updated. {}".format(response)) + if weight_column_spec_name is not None: + response = client.set_weight_column( + dataset_display_name=dataset_display_name, + column_spec_display_name=weight_column_spec_name, + ) + print("Weight column updated. {}".format(response)) + if test_train_column_spec_name is not None: + response = client.set_test_train_column( + dataset_display_name=dataset_display_name, + column_spec_display_name=test_train_column_spec_name, + ) + print("Test/train column updated. {}".format(response)) + + +def delete_dataset(project_id, compute_region, dataset_display_name): + """Delete a dataset""" + # [START automl_tables_delete_dataset] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # dataset_display_name = 'DATASET_DISPLAY_NAME_HERE + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # Delete a dataset. + response = client.delete_dataset(dataset_display_name=dataset_display_name) + + # synchronous check of operation status. + print("Dataset deleted. {}".format(response.result())) + # [END automl_tables_delete_dataset] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + subparsers = parser.add_subparsers(dest="command") + + create_dataset_parser = subparsers.add_parser( + "create_dataset", help=create_dataset.__doc__ + ) + create_dataset_parser.add_argument("--dataset_name") + + list_datasets_parser = subparsers.add_parser( + "list_datasets", help=list_datasets.__doc__ + ) + list_datasets_parser.add_argument("--filter_") + + get_dataset_parser = subparsers.add_parser( + "get_dataset", help=get_dataset.__doc__ + ) + get_dataset_parser.add_argument("--dataset_display_name") + + import_data_parser = subparsers.add_parser( + "import_data", help=import_data.__doc__ + ) + import_data_parser.add_argument("--dataset_display_name") + import_data_parser.add_argument("--path") + + update_dataset_parser = subparsers.add_parser( + "update_dataset", help=update_dataset.__doc__ + ) + update_dataset_parser.add_argument("--dataset_display_name") + update_dataset_parser.add_argument("--target_column_spec_name") + update_dataset_parser.add_argument("--weight_column_spec_name") + update_dataset_parser.add_argument("--ml_use_column_spec_name") + + delete_dataset_parser = subparsers.add_parser( + "delete_dataset", help=delete_dataset.__doc__ + ) + delete_dataset_parser.add_argument("--dataset_display_name") + + project_id = os.environ["PROJECT_ID"] + compute_region = os.environ["REGION_NAME"] + + args = parser.parse_args() + if args.command == "create_dataset": + create_dataset(project_id, compute_region, args.dataset_name) + if args.command == "list_datasets": + list_datasets(project_id, compute_region, args.filter_) + if args.command == "get_dataset": + get_dataset(project_id, compute_region, args.dataset_display_name) + if args.command == "import_data": + import_data( + project_id, compute_region, args.dataset_display_name, args.path + ) + if args.command == "update_dataset": + update_dataset( + project_id, + compute_region, + args.dataset_display_name, + args.target_column_spec_name, + args.weight_column_spec_name, + args.ml_use_column_spec_name, + ) + if args.command == "delete_dataset": + delete_dataset(project_id, compute_region, args.dataset_display_name) diff --git a/automl/tables/automl_tables_model.py b/automl/tables/automl_tables_model.py new file mode 100644 index 00000000000..b3193ff272d --- /dev/null +++ b/automl/tables/automl_tables_model.py @@ -0,0 +1,507 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This application demonstrates how to perform basic operations on model +with the Google AutoML Tables API. + +For more information, the documentation at +https://cloud.google.com/automl-tables/docs. +""" + +import argparse +import os + + +def create_model( + project_id, + compute_region, + dataset_display_name, + model_display_name, + train_budget_milli_node_hours, + include_column_spec_names=None, + exclude_column_spec_names=None, +): + """Create a model.""" + # [START automl_tables_create_model] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # dataset_display_name = 'DATASET_DISPLAY_NAME_HERE' + # model_display_name = 'MODEL_DISPLAY_NAME_HERE' + # train_budget_milli_node_hours = 'TRAIN_BUDGET_MILLI_NODE_HOURS_HERE' + # include_column_spec_names = 'INCLUDE_COLUMN_SPEC_NAMES_HERE' + # or None if unspecified + # exclude_column_spec_names = 'EXCLUDE_COLUMN_SPEC_NAMES_HERE' + # or None if unspecified + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # Create a model with the model metadata in the region. + response = client.create_model( + model_display_name, + train_budget_milli_node_hours=train_budget_milli_node_hours, + dataset_display_name=dataset_display_name, + include_column_spec_names=include_column_spec_names, + exclude_column_spec_names=exclude_column_spec_names, + ) + + print("Training model...") + print("Training operation name: {}".format(response.operation.name)) + print("Training completed: {}".format(response.result())) + + # [END automl_tables_create_model] + + +def get_operation_status(operation_full_id): + """Get operation status.""" + # [START automl_tables_get_operation_status] + # TODO(developer): Uncomment and set the following variables + # operation_full_id = + # 'projects//locations//operations/' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient() + + # Get the latest state of a long-running operation. + op = client.auto_ml_client._transport.operations_client.get_operation( + operation_full_id + ) + + print("Operation status: {}".format(op)) + + # [END automl_tables_get_operation_status] + + +def list_models(project_id, compute_region, filter=None): + """List all models.""" + result = [] + # [START automl_tables_list_models] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # filter = 'DATASET_DISPLAY_NAME_HERE' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # List all the models available in the region by applying filter. + response = client.list_models(filter=filter) + + print("List of models:") + for model in response: + # Retrieve deployment state. + if model.deployment_state == automl.Model.DeploymentState.DEPLOYED: + deployment_state = "deployed" + else: + deployment_state = "undeployed" + + # Display the model information. + print("Model name: {}".format(model.name)) + print("Model id: {}".format(model.name.split("/")[-1])) + print("Model display name: {}".format(model.display_name)) + metadata = model.tables_model_metadata + print( + "Target column display name: {}".format( + metadata.target_column_spec.display_name + ) + ) + print( + "Training budget in node milli hours: {}".format( + metadata.train_budget_milli_node_hours + ) + ) + print( + "Training cost in node milli hours: {}".format( + metadata.train_cost_milli_node_hours + ) + ) + print("Model create time: {}".format(model.create_time)) + print("Model deployment state: {}".format(deployment_state)) + print("\n") + + # [END automl_tables_list_models] + result.append(model) + + return result + + +def get_model(project_id, compute_region, model_display_name): + """Get model details.""" + # [START automl_tables_get_model] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # model_display_name = 'MODEL_DISPLAY_NAME_HERE' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # Get complete detail of the model. + model = client.get_model(model_display_name=model_display_name) + + # Retrieve deployment state. + if model.deployment_state == automl.Model.DeploymentState.DEPLOYED: + deployment_state = "deployed" + else: + deployment_state = "undeployed" + + # get features of top importance + feat_list = [ + (column.feature_importance, column.column_display_name) + for column in model.tables_model_metadata.tables_model_column_info + ] + feat_list.sort(reverse=True) + if len(feat_list) < 10: + feat_to_show = len(feat_list) + else: + feat_to_show = 10 + + # Display the model information. + print("Model name: {}".format(model.name)) + print("Model id: {}".format(model.name.split("/")[-1])) + print("Model display name: {}".format(model.display_name)) + print("Features of top importance:") + for feat in feat_list[:feat_to_show]: + print(feat) + print("Model create time: {}".format(model.create_time)) + print("Model deployment state: {}".format(deployment_state)) + + # [END automl_tables_get_model] + + return model + + +def list_model_evaluations( + project_id, compute_region, model_display_name, filter=None +): + + """List model evaluations.""" + result = [] + # [START automl_tables_list_model_evaluations] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # model_display_name = 'MODEL_DISPLAY_NAME_HERE' + # filter = 'filter expression here' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # List all the model evaluations in the model by applying filter. + response = client.list_model_evaluations( + model_display_name=model_display_name, filter=filter + ) + + print("List of model evaluations:") + for evaluation in response: + print("Model evaluation name: {}".format(evaluation.name)) + print("Model evaluation id: {}".format(evaluation.name.split("/")[-1])) + print( + "Model evaluation example count: {}".format( + evaluation.evaluated_example_count + ) + ) + print("Model evaluation time: {}".format(evaluation.create_time)) + print("\n") + # [END automl_tables_list_model_evaluations] + result.append(evaluation) + + return result + + +def get_model_evaluation( + project_id, compute_region, model_id, model_evaluation_id +): + """Get model evaluation.""" + # [START automl_tables_get_model_evaluation] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # model_id = 'MODEL_ID_HERE' + # model_evaluation_id = 'MODEL_EVALUATION_ID_HERE' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient() + + # Get the full path of the model evaluation. + model_path = client.auto_ml_client.model_path( + project_id, compute_region, model_id + ) + model_evaluation_full_id = f"{model_path}/modelEvaluations/{model_evaluation_id}" + + # Get complete detail of the model evaluation. + response = client.get_model_evaluation( + model_evaluation_name=model_evaluation_full_id + ) + + print(response) + # [END automl_tables_get_model_evaluation] + return response + + +def display_evaluation( + project_id, compute_region, model_display_name, filter=None +): + """Display evaluation.""" + # [START automl_tables_display_evaluation] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # model_display_name = 'MODEL_DISPLAY_NAME_HERE' + # filter = 'filter expression here' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # List all the model evaluations in the model by applying filter. + response = client.list_model_evaluations( + model_display_name=model_display_name, filter=filter + ) + + # Iterate through the results. + for evaluation in response: + # There is evaluation for each class in a model and for overall model. + # Get only the evaluation of overall model. + if not evaluation.annotation_spec_id: + model_evaluation_name = evaluation.name + break + + # Get a model evaluation. + model_evaluation = client.get_model_evaluation( + model_evaluation_name=model_evaluation_name + ) + + classification_metrics = model_evaluation.classification_evaluation_metrics + if str(classification_metrics): + confidence_metrics = classification_metrics.confidence_metrics_entry + + # Showing model score based on threshold of 0.5 + print("Model classification metrics (threshold at 0.5):") + for confidence_metrics_entry in confidence_metrics: + if confidence_metrics_entry.confidence_threshold == 0.5: + print( + "Model Precision: {}%".format( + round(confidence_metrics_entry.precision * 100, 2) + ) + ) + print( + "Model Recall: {}%".format( + round(confidence_metrics_entry.recall * 100, 2) + ) + ) + print( + "Model F1 score: {}%".format( + round(confidence_metrics_entry.f1_score * 100, 2) + ) + ) + print("Model AUPRC: {}".format(classification_metrics.au_prc)) + print("Model AUROC: {}".format(classification_metrics.au_roc)) + print("Model log loss: {}".format(classification_metrics.log_loss)) + + regression_metrics = model_evaluation.regression_evaluation_metrics + if str(regression_metrics): + print("Model regression metrics:") + print( + "Model RMSE: {}".format(regression_metrics.root_mean_squared_error) + ) + print("Model MAE: {}".format(regression_metrics.mean_absolute_error)) + print( + "Model MAPE: {}".format( + regression_metrics.mean_absolute_percentage_error + ) + ) + print("Model R^2: {}".format(regression_metrics.r_squared)) + + # [END automl_tables_display_evaluation] + + +def deploy_model(project_id, compute_region, model_display_name): + """Deploy model.""" + # [START automl_tables_deploy_model] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # model_display_name = 'MODEL_DISPLAY_NAME_HERE' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # Deploy model + response = client.deploy_model(model_display_name=model_display_name) + + # synchronous check of operation status. + print("Model deployed. {}".format(response.result())) + + # [END automl_tables_deploy_model] + + +def undeploy_model(project_id, compute_region, model_display_name): + """Undeploy model.""" + # [START automl_tables_undeploy_model] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # model_display_name = 'MODEL_DISPLAY_NAME_HERE' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # Undeploy model + response = client.undeploy_model(model_display_name=model_display_name) + + # synchronous check of operation status. + print("Model undeployed. {}".format(response.result())) + + # [END automl_tables_undeploy_model] + + +def delete_model(project_id, compute_region, model_display_name): + """Delete a model.""" + # [START automl_tables_delete_model] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # model_display_name = 'MODEL_DISPLAY_NAME_HERE' + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # Undeploy model + response = client.delete_model(model_display_name=model_display_name) + + # synchronous check of operation status. + print("Model deleted. {}".format(response.result())) + + # [END automl_tables_delete_model] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + subparsers = parser.add_subparsers(dest="command") + + create_model_parser = subparsers.add_parser( + "create_model", help=create_model.__doc__ + ) + create_model_parser.add_argument("--dataset_display_name") + create_model_parser.add_argument("--model_display_name") + create_model_parser.add_argument( + "--train_budget_milli_node_hours", type=int + ) + + get_operation_status_parser = subparsers.add_parser( + "get_operation_status", help=get_operation_status.__doc__ + ) + get_operation_status_parser.add_argument("--operation_full_id") + + list_models_parser = subparsers.add_parser( + "list_models", help=list_models.__doc__ + ) + list_models_parser.add_argument("--filter_") + + get_model_parser = subparsers.add_parser( + "get_model", help=get_model.__doc__ + ) + get_model_parser.add_argument("--model_display_name") + + list_model_evaluations_parser = subparsers.add_parser( + "list_model_evaluations", help=list_model_evaluations.__doc__ + ) + list_model_evaluations_parser.add_argument("--model_display_name") + list_model_evaluations_parser.add_argument("--filter_") + + get_model_evaluation_parser = subparsers.add_parser( + "get_model_evaluation", help=get_model_evaluation.__doc__ + ) + get_model_evaluation_parser.add_argument("--model_id") + get_model_evaluation_parser.add_argument("--model_evaluation_id") + + display_evaluation_parser = subparsers.add_parser( + "display_evaluation", help=display_evaluation.__doc__ + ) + display_evaluation_parser.add_argument("--model_display_name") + display_evaluation_parser.add_argument("--filter_") + + deploy_model_parser = subparsers.add_parser( + "deploy_model", help=deploy_model.__doc__ + ) + deploy_model_parser.add_argument("--model_display_name") + + undeploy_model_parser = subparsers.add_parser( + "undeploy_model", help=undeploy_model.__doc__ + ) + undeploy_model_parser.add_argument("--model_display_name") + + delete_model_parser = subparsers.add_parser( + "delete_model", help=delete_model.__doc__ + ) + delete_model_parser.add_argument("--model_display_name") + + project_id = os.environ["PROJECT_ID"] + compute_region = os.environ["REGION_NAME"] + + args = parser.parse_args() + + if args.command == "create_model": + create_model( + project_id, + compute_region, + args.dataset_display_name, + args.model_display_name, + args.train_budget_milli_node_hours, + # Input columns are omitted here as argparse does not support + # column spec objects, but it is still included in function def. + ) + if args.command == "get_operation_status": + get_operation_status(args.operation_full_id) + if args.command == "list_models": + list_models(project_id, compute_region, args.filter_) + if args.command == "get_model": + get_model(project_id, compute_region, args.model_display_name) + if args.command == "list_model_evaluations": + list_model_evaluations( + project_id, compute_region, args.model_display_name, args.filter_ + ) + if args.command == "get_model_evaluation": + get_model_evaluation( + project_id, + compute_region, + args.model_display_name, + args.model_evaluation_id, + ) + if args.command == "display_evaluation": + display_evaluation( + project_id, compute_region, args.model_display_name, args.filter_ + ) + if args.command == "deploy_model": + deploy_model(project_id, compute_region, args.model_display_name) + if args.command == "undeploy_model": + undeploy_model(project_id, compute_region, args.model_display_name) + if args.command == "delete_model": + delete_model(project_id, compute_region, args.model_display_name) diff --git a/automl/tables/automl_tables_predict.py b/automl/tables/automl_tables_predict.py new file mode 100644 index 00000000000..a330213c81b --- /dev/null +++ b/automl/tables/automl_tables_predict.py @@ -0,0 +1,209 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This application demonstrates how to perform basic operations on prediction +with the Google AutoML Tables API. + +For more information, the documentation at +https://cloud.google.com/automl-tables/docs. +""" + +import argparse +import os + + +def predict( + project_id, + compute_region, + model_display_name, + inputs, + feature_importance=None, +): + """Make a prediction.""" + # [START automl_tables_predict] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # model_display_name = 'MODEL_DISPLAY_NAME_HERE' + # inputs = {'value': 3, ...} + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + if feature_importance: + response = client.predict( + model_display_name=model_display_name, + inputs=inputs, + feature_importance=True, + ) + else: + response = client.predict( + model_display_name=model_display_name, inputs=inputs + ) + + print("Prediction results:") + for result in response.payload: + print( + "Predicted class name: {}".format(result.tables.value) + ) + print("Predicted class score: {}".format(result.tables.score)) + + if feature_importance: + # get features of top importance + feat_list = [ + (column.feature_importance, column.column_display_name) + for column in result.tables.tables_model_column_info + ] + feat_list.sort(reverse=True) + if len(feat_list) < 10: + feat_to_show = len(feat_list) + else: + feat_to_show = 10 + + print("Features of top importance:") + for feat in feat_list[:feat_to_show]: + print(feat) + + # [END automl_tables_predict] + + +def batch_predict_bq( + project_id, + compute_region, + model_display_name, + bq_input_uri, + bq_output_uri, + params +): + """Make a batch of predictions.""" + # [START automl_tables_batch_predict_bq] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # model_display_name = 'MODEL_DISPLAY_NAME_HERE' + # bq_input_uri = 'bq://my-project.my-dataset.my-table' + # bq_output_uri = 'bq://my-project' + # params = {} + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # Query model + response = client.batch_predict(bigquery_input_uri=bq_input_uri, + bigquery_output_uri=bq_output_uri, + model_display_name=model_display_name, + params=params) + print("Making batch prediction... ") + # `response` is a async operation descriptor, + # you can register a callback for the operation to complete via `add_done_callback`: + # def callback(operation_future): + # result = operation_future.result() + # response.add_done_callback(callback) + # + # or block the thread polling for the operation's results: + response.result() + # AutoML puts predictions in a newly generated dataset with a name by a mask "prediction_" + model_id + "_" + timestamp + # here's how to get the dataset name: + dataset_name = response.metadata.batch_predict_details.output_info.bigquery_output_dataset + + print("Batch prediction complete.\nResults are in '{}' dataset.\n{}".format( + dataset_name, response.metadata)) + + # [END automl_tables_batch_predict_bq] + + +def batch_predict( + project_id, + compute_region, + model_display_name, + gcs_input_uri, + gcs_output_uri, + params, +): + """Make a batch of predictions.""" + # [START automl_tables_batch_predict] + # TODO(developer): Uncomment and set the following variables + # project_id = 'PROJECT_ID_HERE' + # compute_region = 'COMPUTE_REGION_HERE' + # model_display_name = 'MODEL_DISPLAY_NAME_HERE' + # gcs_input_uri = 'gs://YOUR_BUCKET_ID/path_to_your_input_csv' + # gcs_output_uri = 'gs://YOUR_BUCKET_ID/path_to_save_results/' + # params = {} + + from google.cloud import automl_v1beta1 as automl + + client = automl.TablesClient(project=project_id, region=compute_region) + + # Query model + response = client.batch_predict( + gcs_input_uris=gcs_input_uri, + gcs_output_uri_prefix=gcs_output_uri, + model_display_name=model_display_name, + params=params + ) + print("Making batch prediction... ") + # `response` is a async operation descriptor, + # you can register a callback for the operation to complete via `add_done_callback`: + # def callback(operation_future): + # result = operation_future.result() + # response.add_done_callback(callback) + # + # or block the thread polling for the operation's results: + response.result() + + print("Batch prediction complete.\n{}".format(response.metadata)) + + # [END automl_tables_batch_predict] + + +if __name__ == "__main__": + parser = argparse.ArgumentParser( + description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter, + ) + subparsers = parser.add_subparsers(dest="command") + + predict_parser = subparsers.add_parser("predict", help=predict.__doc__) + predict_parser.add_argument("--model_display_name") + predict_parser.add_argument("--file_path") + + batch_predict_parser = subparsers.add_parser( + "batch_predict", help=predict.__doc__ + ) + batch_predict_parser.add_argument("--model_display_name") + batch_predict_parser.add_argument("--input_path") + batch_predict_parser.add_argument("--output_path") + + project_id = os.environ["PROJECT_ID"] + compute_region = os.environ["REGION_NAME"] + + args = parser.parse_args() + + if args.command == "predict": + predict( + project_id, compute_region, args.model_display_name, args.file_path + ) + + if args.command == "batch_predict": + batch_predict( + project_id, + compute_region, + args.model_display_name, + args.input_path, + args.output_path, + ) diff --git a/automl/tables/automl_tables_set_endpoint.py b/automl/tables/automl_tables_set_endpoint.py new file mode 100644 index 00000000000..d6ab898b4f5 --- /dev/null +++ b/automl/tables/automl_tables_set_endpoint.py @@ -0,0 +1,33 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +def create_client_with_endpoint(gcp_project_id): + """Create a Tables client with a non-default endpoint.""" + # [START automl_set_endpoint] + from google.cloud import automl_v1beta1 as automl + from google.api_core.client_options import ClientOptions + + # Set the endpoint you want to use via the ClientOptions. + # gcp_project_id = 'YOUR_PROJECT_ID' + client_options = ClientOptions(api_endpoint="eu-automl.googleapis.com:443") + client = automl.TablesClient( + project=gcp_project_id, region="eu", client_options=client_options + ) + # [END automl_set_endpoint] + + # do simple test to check client connectivity + print(client.list_datasets()) + + return client diff --git a/automl/tables/batch_predict_test.py b/automl/tables/batch_predict_test.py new file mode 100644 index 00000000000..e3692cb6301 --- /dev/null +++ b/automl/tables/batch_predict_test.py @@ -0,0 +1,64 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +from google.cloud.automl_v1beta1 import Model + +import pytest + +import automl_tables_model +import automl_tables_predict +import model_test + + +PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] +REGION = "us-central1" +STATIC_MODEL = model_test.STATIC_MODEL +GCS_INPUT = "gs://{}-automl-tables-test/bank-marketing.csv".format(PROJECT) +GCS_OUTPUT = "gs://{}-automl-tables-test/TABLE_TEST_OUTPUT/".format(PROJECT) +BQ_INPUT = "bq://{}.automl_test.bank_marketing".format(PROJECT) +BQ_OUTPUT = "bq://{}".format(PROJECT) +PARAMS = {} + + +@pytest.mark.slow +def test_batch_predict(capsys): + ensure_model_online() + + automl_tables_predict.batch_predict( + PROJECT, REGION, STATIC_MODEL, GCS_INPUT, GCS_OUTPUT, PARAMS + ) + out, _ = capsys.readouterr() + assert "Batch prediction complete" in out + + +@pytest.mark.slow +def test_batch_predict_bq(capsys): + ensure_model_online() + automl_tables_predict.batch_predict_bq( + PROJECT, REGION, STATIC_MODEL, BQ_INPUT, BQ_OUTPUT, PARAMS + ) + out, _ = capsys.readouterr() + assert "Batch prediction complete" in out + + +def ensure_model_online(): + model = model_test.ensure_model_ready() + if model.deployment_state != Model.DeploymentState.DEPLOYED: + automl_tables_model.deploy_model(PROJECT, REGION, model.display_name) + + return automl_tables_model.get_model(PROJECT, REGION, model.display_name) diff --git a/automl/tables/dataset_test.py b/automl/tables/dataset_test.py new file mode 100644 index 00000000000..27570f0bee9 --- /dev/null +++ b/automl/tables/dataset_test.py @@ -0,0 +1,112 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import random +import string +import time + +from google.api_core import exceptions +import pytest + +import automl_tables_dataset + + +PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] +REGION = "us-central1" +STATIC_DATASET = "do_not_delete_this_table_python" +GCS_DATASET = ("gs://python-docs-samples-tests-automl-tables-test" + "/bank-marketing.csv") + +ID = "{rand}_{time}".format( + rand="".join( + [random.choice(string.ascii_letters + string.digits) for n in range(4)] + ), + time=int(time.time()), +) + + +def _id(name): + return "{}_{}".format(name, ID) + + +def ensure_dataset_ready(): + dataset = None + name = STATIC_DATASET + try: + dataset = automl_tables_dataset.get_dataset(PROJECT, REGION, name) + except exceptions.NotFound: + dataset = automl_tables_dataset.create_dataset(PROJECT, REGION, name) + + if dataset.example_count is None or dataset.example_count == 0: + automl_tables_dataset.import_data(PROJECT, REGION, name, GCS_DATASET) + dataset = automl_tables_dataset.get_dataset(PROJECT, REGION, name) + + automl_tables_dataset.update_dataset( + PROJECT, + REGION, + dataset.display_name, + target_column_spec_name="Deposit", + ) + + return dataset + + +@pytest.mark.slow +def test_dataset_create_import_delete(capsys): + name = _id("d_cr_dl") + dataset = automl_tables_dataset.create_dataset(PROJECT, REGION, name) + assert dataset is not None + assert dataset.display_name == name + + automl_tables_dataset.import_data(PROJECT, REGION, name, GCS_DATASET) + + out, _ = capsys.readouterr() + assert "Data imported." in out + + automl_tables_dataset.delete_dataset(PROJECT, REGION, name) + + with pytest.raises(exceptions.NotFound): + automl_tables_dataset.get_dataset(PROJECT, REGION, name) + + +def test_dataset_update(capsys): + dataset = ensure_dataset_ready() + automl_tables_dataset.update_dataset( + PROJECT, + REGION, + dataset.display_name, + target_column_spec_name="Deposit", + weight_column_spec_name="Balance", + ) + + out, _ = capsys.readouterr() + assert "Target column updated." in out + assert "Weight column updated." in out + + +def test_list_datasets(): + ensure_dataset_ready() + assert ( + next( + ( + d + for d in automl_tables_dataset.list_datasets(PROJECT, REGION) + if d.display_name == STATIC_DATASET + ), + None, + ) + is not None + ) diff --git a/automl/tables/endpoint_test.py b/automl/tables/endpoint_test.py new file mode 100644 index 00000000000..6af6b8da084 --- /dev/null +++ b/automl/tables/endpoint_test.py @@ -0,0 +1,26 @@ +#!/usr/bin/env python + +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os + +import automl_tables_set_endpoint + +PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] + + +def test_client_creation(capsys): + automl_tables_set_endpoint.create_client_with_endpoint(PROJECT) + out, _ = capsys.readouterr() + assert "ListDatasetsPager" in out diff --git a/automl/tables/model_test.py b/automl/tables/model_test.py new file mode 100644 index 00000000000..484eaf82487 --- /dev/null +++ b/automl/tables/model_test.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import os +import random +import string +import time + +from google.api_core import exceptions + +import automl_tables_model +import dataset_test + + +PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] +REGION = "us-central1" +STATIC_MODEL = "do_not_delete_this_model_0" +GCS_DATASET = "gs://cloud-ml-tables-data/bank-marketing.csv" + +ID = "{rand}_{time}".format( + rand="".join( + [random.choice(string.ascii_letters + string.digits) for n in range(4)] + ), + time=int(time.time()), +) + + +def _id(name): + return "{}_{}".format(name, ID) + + +def test_list_models(): + ensure_model_ready() + assert ( + next( + ( + m + for m in automl_tables_model.list_models(PROJECT, REGION) + if m.display_name == STATIC_MODEL + ), + None, + ) + is not None + ) + + +def test_list_model_evaluations(): + model = ensure_model_ready() + mes = automl_tables_model.list_model_evaluations( + PROJECT, REGION, model.display_name + ) + assert len(mes) > 0 + for me in mes: + assert me.name.startswith(model.name) + + +def test_get_model_evaluations(): + model = ensure_model_ready() + me = automl_tables_model.list_model_evaluations( + PROJECT, REGION, model.display_name + )[0] + mep = automl_tables_model.get_model_evaluation( + PROJECT, + REGION, + model.name.rpartition("/")[2], + me.name.rpartition("/")[2], + ) + + assert mep.name == me.name + + +def ensure_model_ready(): + name = STATIC_MODEL + try: + return automl_tables_model.get_model(PROJECT, REGION, name) + except exceptions.NotFound: + pass + + dataset = dataset_test.ensure_dataset_ready() + return automl_tables_model.create_model( + PROJECT, REGION, dataset.display_name, name, 1000 + ) diff --git a/automl/tables/predict_test.py b/automl/tables/predict_test.py new file mode 100644 index 00000000000..42bfd89cb11 --- /dev/null +++ b/automl/tables/predict_test.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os + +import backoff + +from google.cloud.automl_v1beta1 import Model + +import automl_tables_model +import automl_tables_predict +import model_test + +PROJECT = os.environ["GOOGLE_CLOUD_PROJECT"] +REGION = "us-central1" +STATIC_MODEL = model_test.STATIC_MODEL +MAX_TIMEOUT = 200 + + +@backoff.on_exception( + wait_gen=lambda: (wait_time for wait_time in [50, 150, MAX_TIMEOUT]), + exception=Exception, + max_tries=3, +) +def test_predict(capsys): + inputs = { + "Age": 31, + "Balance": 200, + "Campaign": 2, + "Contact": "cellular", + "Day": "4", + "Default": "no", + "Duration": 12, + "Education": "primary", + "Housing": "yes", + "Job": "blue-collar", + "Loan": "no", + "MaritalStatus": "divorced", + "Month": "jul", + "PDays": 4, + "POutcome": "0", + "Previous": 12, + } + + ensure_model_online() + automl_tables_predict.predict(PROJECT, REGION, STATIC_MODEL, inputs, True) + out, _ = capsys.readouterr() + assert "Predicted class name:" in out + assert "Predicted class score:" in out + assert "Features of top importance:" in out + + +def ensure_model_online(): + model = model_test.ensure_model_ready() + if model.deployment_state != Model.DeploymentState.DEPLOYED: + automl_tables_model.deploy_model(PROJECT, REGION, model.display_name) + + return automl_tables_model.get_model(PROJECT, REGION, model.display_name) diff --git a/automl/tables/requirements-test.txt b/automl/tables/requirements-test.txt new file mode 100644 index 00000000000..ee41191cbd4 --- /dev/null +++ b/automl/tables/requirements-test.txt @@ -0,0 +1,2 @@ +pytest==7.2.0 +backoff==2.2.1 \ No newline at end of file diff --git a/automl/tables/requirements.txt b/automl/tables/requirements.txt new file mode 100644 index 00000000000..53c7a53d7d7 --- /dev/null +++ b/automl/tables/requirements.txt @@ -0,0 +1 @@ +google-cloud-automl==2.8.3 diff --git a/automl/vision_edge/edge_container_predict/Dockerfile b/automl/vision_edge/edge_container_predict/Dockerfile new file mode 100644 index 00000000000..d447bcc5754 --- /dev/null +++ b/automl/vision_edge/edge_container_predict/Dockerfile @@ -0,0 +1,29 @@ +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +ARG TF_SERVING_IMAGE_TAG +FROM tensorflow/serving:${TF_SERVING_IMAGE_TAG} + +ENV GCS_READ_CACHE_MAX_STALENESS 300 +ENV GCS_STAT_CACHE_MAX_AGE 300 +ENV GCS_MATCHING_PATHS_CACHE_MAX_AGE 300 + +EXPOSE 8500 +EXPOSE 8501 +ENTRYPOINT /usr/bin/tensorflow_model_server \ + --port=8500 \ + --rest_api_port=8501 \ + --model_base_path=/tmp/mounted_model/ \ + --tensorflow_session_parallelism=0 \ + --file_system_poll_wait_seconds=31540000 diff --git a/automl/vision_edge/edge_container_predict/README.md b/automl/vision_edge/edge_container_predict/README.md new file mode 100644 index 00000000000..da8cc50ed66 --- /dev/null +++ b/automl/vision_edge/edge_container_predict/README.md @@ -0,0 +1,78 @@ +# AutoML Vision Edge Container Prediction + +This is an example to show how to predict with AutoML Vision Edge Containers. +The test (automl_vision_edge_container_predict_test.py) shows an automatical way +to run the prediction. + +If you want to try the test manually with a sample model, please install +[gsutil tools](https://cloud.google.com/storage/docs/gsutil_install) and +[Docker CE](https://docs.docker.com/install/) first, and then follow the steps +below. All the following instructions with commands assume you are in this +folder with system variables as + +```bash +$ CONTAINER_NAME=AutomlVisionEdgeContainerPredict +$ PORT=8505 +``` + ++ Step 1. Pull the Docker image. + +```bash +# This is a CPU TFServing 1.14.0 with some default settings compiled from +# https://hub.docker.com/r/tensorflow/serving. +$ DOCKER_GCS_DIR=gcr.io/cloud-devrel-public-resources +$ CPU_DOCKER_GCS_PATH=${DOCKER_GCS_DIR}/gcloud-container-1.14.0:latest +$ sudo docker pull ${CPU_DOCKER_GCS_PATH} +``` + ++ Step 2. Get a sample saved model. + +```bash +$ MODEL_GCS_DIR=gs://cloud-samples-data/vision/edge_container_predict +$ SAMPLE_SAVED_MODEL=${MODEL_GCS_DIR}/saved_model.pb +$ mkdir model_path +$ YOUR_MODEL_PATH=$(realpath model_path) +$ gsutil -m cp ${SAMPLE_SAVED_MODEL} ${YOUR_MODEL_PATH} +``` + ++ Step 3. Run the Docker container. + +```bash +$ sudo docker run --rm --name ${CONTAINER_NAME} -p ${PORT}:8501 -v \ + ${YOUR_MODEL_PATH}:/tmp/mounted_model/0001 -t ${CPU_DOCKER_GCS_PATH} +``` + ++ Step 4. Send a prediction request. + +```bash +$ python automl_vision_edge_container_predict.py --image_file_path=./test.jpg \ + --image_key=1 --port_number=${PORT} +``` + +The outputs are + +``` +{ + 'predictions': + [ + { + 'scores': [0.0914393, 0.458942, 0.027604, 0.386767, 0.0352474], + labels': ['daisy', 'dandelion', 'roses', 'sunflowers', 'tulips'], + 'key': '1' + } + ] +} +``` + ++ Step 5. Stop the container. + +```bash +sudo docker stop ${CONTAINER_NAME} +``` + +Note: The docker image is uploaded with the following command. + +```bash +gcloud builds --project=cloud-devrel-public-resources \ + submit --config cloudbuild.yaml +``` diff --git a/automl/vision_edge/edge_container_predict/automl_vision_edge_container_predict.py b/automl/vision_edge/edge_container_predict/automl_vision_edge_container_predict.py new file mode 100644 index 00000000000..7ad2d19390a --- /dev/null +++ b/automl/vision_edge/edge_container_predict/automl_vision_edge_container_predict.py @@ -0,0 +1,113 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +r"""This is an example to call REST API from TFServing docker containers. + +Examples: + python automl_vision_edge_container_predict.py \ + --image_file_path=./test.jpg --image_key=1 --port_number=8501 + +""" + +import argparse +# [START automl_vision_edge_container_predict] +import base64 +import cv2 +import io +import json + +import requests + +def preprocess_image(image_file_path, max_width, max_height): + """Preprocesses input images for AutoML Vision Edge models. + + Args: + image_file_path: Path to a local image for the prediction request. + max_width: The max width for preprocessed images. The max width is 640 + (1024) for AutoML Vision Image Classfication (Object Detection) + models. + max_height: The max width for preprocessed images. The max height is + 480 (1024) for AutoML Vision Image Classfication (Object + Detetion) models. + Returns: + The preprocessed encoded image bytes. + """ + # cv2 is used to read, resize and encode images. + encode_param = [int(cv2.IMWRITE_JPEG_QUALITY), 85] + im = cv2.imread(image_file_path) + [height, width, _] = im.shape + if height > max_height or width > max_width: + ratio = max(height / float(max_width), width / float(max_height)) + new_height = int(height / ratio + 0.5) + new_width = int(width / ratio + 0.5) + resized_im = cv2.resize( + im, (new_width, new_height), interpolation=cv2.INTER_AREA) + _, processed_image = cv2.imencode('.jpg', resized_im, encode_param) + else: + _, processed_image = cv2.imencode('.jpg', im, encode_param) + return base64.b64encode(processed_image).decode('utf-8') + + +def container_predict(image_file_path, image_key, port_number=8501): + """Sends a prediction request to TFServing docker container REST API. + + Args: + image_file_path: Path to a local image for the prediction request. + image_key: Your chosen string key to identify the given image. + port_number: The port number on your device to accept REST API calls. + Returns: + The response of the prediction request. + """ + # AutoML Vision Edge models will preprocess the input images. + # The max width and height for AutoML Vision Image Classification and + # Object Detection models are 640*480 and 1024*1024 separately. The + # example here is for Image Classification models. + encoded_image = preprocess_image( + image_file_path=image_file_path, max_width=640, max_height=480) + + # The example here only shows prediction with one image. You can extend it + # to predict with a batch of images indicated by different keys, which can + # make sure that the responses corresponding to the given image. + instances = { + 'instances': [ + {'image_bytes': {'b64': str(encoded_image)}, + 'key': image_key} + ] + } + + # This example shows sending requests in the same server that you start + # docker containers. If you would like to send requests to other servers, + # please change localhost to IP of other servers. + url = 'http://localhost:{}/v1/models/default:predict'.format(port_number) + + response = requests.post(url, data=json.dumps(instances)) + print(response.json()) + # [END automl_vision_edge_container_predict] + return response.json() + + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument('--image_file_path', type=str) + parser.add_argument('--image_key', type=str, default='1') + parser.add_argument('--port_number', type=int, default=8501) + args = parser.parse_args() + + container_predict(args.image_file_path, args.image_key, args.port_number) + + +if __name__ == '__main__': + main() diff --git a/automl/vision_edge/edge_container_predict/automl_vision_edge_container_predict_test.py b/automl/vision_edge/edge_container_predict/automl_vision_edge_container_predict_test.py new file mode 100644 index 00000000000..327513c034b --- /dev/null +++ b/automl/vision_edge/edge_container_predict/automl_vision_edge_container_predict_test.py @@ -0,0 +1,108 @@ +#!/usr/bin/env python + +# Copyright 2019 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""Tests for automl_vision_edge_container_predict. + +The test will automatically start a container with a sample saved_model.pb, +send a request with one image, verify the response and delete the started +container. + +If you want to try the test, please install +[gsutil tools](https://cloud.google.com/storage/docs/gsutil_install) and +[Docker CE](https://docs.docker.com/install/) first. + +Examples: +sudo python -m pytest automl_vision_edge_container_predict_test.py +""" + +import os +import subprocess +import tempfile +import time + +import pytest + +import automl_vision_edge_container_predict as predict # noqa + + +IMAGE_FILE_PATH = os.path.join(os.path.dirname(__file__), 'test.jpg') +# The cpu docker gcs path is from 'Edge container tutorial'. +CPU_DOCKER_GCS_PATH = '{}'.format( + 'gcr.io/cloud-devrel-public-resources/gcloud-container-1.14.0:latest') +# The path of a sample saved model. +SAMPLE_SAVED_MODEL = '{}'.format( + 'gs://cloud-samples-data/vision/edge_container_predict/saved_model.pb') +# Container Name. +NAME = 'AutomlVisionEdgeContainerPredictTest' +# Port Number. +PORT_NUMBER = 8505 + + +@pytest.fixture +def edge_container_predict_server_port(): + # set up + # Pull the CPU docker. + subprocess.check_output( + ['docker', 'pull', CPU_DOCKER_GCS_PATH], + env={'DOCKER_API_VERSION': '1.38'}) + + if os.environ.get('TRAMPOLINE_VERSION'): + # Use /tmp + model_path = tempfile.TemporaryDirectory() + else: + # Use project directory with Trampoline V1. + model_path = tempfile.TemporaryDirectory(dir=os.path.dirname(__file__)) + print("Using model_path: {}".format(model_path)) + # Get the sample saved model. + subprocess.check_output( + ['gsutil', '-m', 'cp', SAMPLE_SAVED_MODEL, model_path.name]) + + # Start the CPU docker. + subprocess.Popen(['docker', 'run', '--rm', '--name', NAME, '-v', + model_path.name + ':/tmp/mounted_model/0001', '-p', + str(PORT_NUMBER) + ':8501', '-t', + CPU_DOCKER_GCS_PATH], + env={'DOCKER_API_VERSION': '1.38'}) + # Sleep a few seconds to wait for the container running. + time.sleep(10) + + yield PORT_NUMBER + + # tear down + # Stop the container. + subprocess.check_output( + ['docker', 'stop', NAME], env={'DOCKER_API_VERSION': '1.38'}) + # Remove the docker image. + subprocess.check_output( + ['docker', 'rmi', CPU_DOCKER_GCS_PATH], + env={'DOCKER_API_VERSION': '1.38'}) + # Remove the temporery directory. + model_path.cleanup() + + +def test_edge_container_predict(capsys, edge_container_predict_server_port): + # If you send requests with one image each time, the key value does not + # matter. If you send requests with multiple images, please used different + # keys to indicated different images, which can make sure that the + # responses corresponding to the given image. + image_key = '1' + # Send a request. + response = predict.container_predict( + IMAGE_FILE_PATH, image_key, PORT_NUMBER) + # Verify the response. + assert 'predictions' in response + assert 'key' in response['predictions'][0] + assert image_key == response['predictions'][0]['key'] diff --git a/automl/vision_edge/edge_container_predict/cloudbuild.yaml b/automl/vision_edge/edge_container_predict/cloudbuild.yaml new file mode 100644 index 00000000000..5b0760254b4 --- /dev/null +++ b/automl/vision_edge/edge_container_predict/cloudbuild.yaml @@ -0,0 +1,26 @@ +# Copyright 2020 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +timeout: 3600s + +steps: + - name: 'gcr.io/cloud-builders/docker' + args: ['build', '-t', 'gcr.io/$PROJECT_ID/gcloud-container-1.14.0', + '--build-arg', 'TF_SERVING_IMAGE_TAG=1.14.0', '.'] + - name: 'gcr.io/cloud-builders/docker' + args: ['build', '-t', 'gcr.io/$PROJECT_ID/gcloud-container-1.14.0-gpu', + '--build-arg', 'TF_SERVING_IMAGE_TAG=1.14.0-gpu', '.'] +images: + - 'gcr.io/$PROJECT_ID/gcloud-container-1.14.0' + - 'gcr.io/$PROJECT_ID/gcloud-container-1.14.0-gpu' diff --git a/automl/vision_edge/edge_container_predict/test.jpg b/automl/vision_edge/edge_container_predict/test.jpg new file mode 100644 index 00000000000..4873e8d1b52 Binary files /dev/null and b/automl/vision_edge/edge_container_predict/test.jpg differ diff --git a/automl/vision_edge/resources/test.png b/automl/vision_edge/resources/test.png new file mode 100644 index 00000000000..653342a46e5 Binary files /dev/null and b/automl/vision_edge/resources/test.png differ