From 24b693d5516d268283a4cd5f747e5037dcd97c38 Mon Sep 17 00:00:00 2001 From: Shabir Mohamed Abdul Samadh <7249208+Shabirmean@users.noreply.github.com> Date: Tue, 20 Dec 2022 16:10:16 -0500 Subject: [PATCH] samples: migrate code from googleapis/java-aiplatform (#7451) ### Migrating samples from [googleapis/java-aiplatform](https://togithub.com/googleapis/java-aiplatform/tree/main/samples) into [java-docs-samples/aiplatform](https://togithub.com/GoogleCloudPlatform/java-docs-samples) --- - feat: initial code generation - chore(deps): update dependency com.google.cloud.samples:shared-configuration to v1.0.18 (#2) - chore(deps): update dependency com.google.cloud.samples:shared-configuration to v1.0.19 (#11) - samples: update pom.xml (s) in the samples dir (#24) - chore(deps): update dependency com.google.cloud.samples:shared-configuration to v1.0.21 (#14) - test(deps): update dependency junit:junit to v4.13.1 - test(deps): update dependency com.google.truth:truth to v1.1 (#33) - deps: update dependency com.google.cloud:google-cloud-storage to v1.113.2 (#38) - samples: ucaip samples batch 3 of 6 (#18) - samples: ucaip batch samples 4 of 6 (#19) - samples: ucaip batch samples 5 of 6 (#20) - samples: ucaip samples batch 6 of 6 (#17) - samples: ucaip sample batch 2 of 6 (#15) - chore: delete ununsed format script (#48) - samples: initial commit and it is missing env vars for testing (#7) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v0.1.0 (#59) - samples(deps): update dependency com.google.cloud:google-cloud-storage to v1.113.3 (#55) - samples(deps): update dependency com.google.protobuf:protobuf-java-util to v4.0.0-rc-2 (#27) - samples: adds custom model, action recognition samples and tests (#111) - feat: adds ValueConverter utility and demo samples (#108) - samples(deps): update dependency com.google.cloud:google-cloud-storage to v1.113.8 (#72) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v0.2.0 (#133) - test(deps): update dependency com.google.truth:truth to v1.1.2 (#138) - samples: adds enhanced library samples (#134) - test(deps): update dependency junit:junit to v4.13.2 (#161) - deps: update dependency com.google.cloud:google-cloud-storage to v1.113.9 (#132) - fix: reduces image object detection test resource file size (#154) - deps: update dependency com.google.cloud:google-cloud-storage to v1.113.10 (#164) - feat: updates library for v1 service (#157) - deps: update dependency com.google.cloud:google-cloud-storage to v1.113.11 (#175) - docs: updates prediction to new hostname (#173) - chore: replaced hard-coded values with env vars (#185) - deps: update dependency com.google.cloud:google-cloud-storage to v1.113.12 (#186) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v0.3.0 (#188) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.3.0 (#189) - deps: update dependency com.google.cloud:google-cloud-storage to v1.113.14 (#202) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v0.4.0 (#209) - chore(deps): update dependency com.google.cloud.samples:shared-configuration to v1.0.22 (#223) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.4.0 (#210) - deps: update dependency com.google.cloud:google-cloud-storage to v1.113.15 (#232) - samples: updates samples to v1 (1 of 8) (#206) - samples: updates samples to v1 (2 of 8) (#212) - test(teardown): refactored teardown section of test (#254) - test(env var): added missing requireEnv val (#255) - samples: updates samples to v1 (3 of 8) (#215) - samples: updates samples to v1 (5 of 10) (#235) - samples: updates samples to v1 (4 of 10) (#233) - deps: update dependency com.google.cloud:google-cloud-storage to v1.113.16 (#334) - chore: Increasing timeout createdataset (#337) - samples: updates samples to v1 (7 of 10) (#238) - samples: updates samples to v1 (6 of 10) (#236) - samples: updates samples to v1 (8 of 8) (#239) - deps: update dependency com.google.cloud:google-cloud-storage to v1.114.0 (#349) - deps: update dependency com.google.code.gson:gson to v2.8.7 (#382) - test(deps): update dependency com.google.truth:truth to v1.1.3 (#383) - chore: changes product name to 'Vertex AI' (#373) - chore(deps): update dependency com.google.cloud.samples:shared-configuration to v1.0.23 (#399) - deps: update dependency com.google.cloud:google-cloud-storage to v1.115.0 (#396) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v1 (#406) - chore: disabling ITs to reduce cost & resolve quota issue (#421) - deps: update dependency com.google.cloud:google-cloud-storage to v1.117.1 (#422) - test: Refactor teardown (#424) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.5.1 (#428) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v1.0.2 (#427) - deps: update dependency com.google.cloud:google-cloud-storage to v1.118.0 (#440) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.5.2 (#434) - deps: update dependency com.google.cloud:google-cloud-storage to v2 (#610) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2 (#609) - deps: update dependency com.google.cloud:google-cloud-storage to v2.0.1 (#612) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.6.0 (#608) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.0.1 (#616) - deps: update dependency com.google.code.gson:gson to v2.8.8 (#622) - deps: update dependency com.google.cloud:google-cloud-storage to v2.0.2 (#621) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.6.1 (#617) - deps: update dependency com.google.cloud:google-cloud-storage to v2.1.0 (#630) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.6.2 (#629) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.0.2 (#628) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.1.0 (#640) - deps: update dependency com.google.cloud:google-cloud-storage to v2.1.1 (#644) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.2.0 (#650) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.8.0 (#641) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.2.1 (#660) - deps: update dependency com.google.cloud:google-cloud-storage to v2.1.2 (#662) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.8.1 (#661) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.8.2 (#666) - deps: update dependency com.google.cloud:google-cloud-storage to v2.1.3 (#667) - deps: update dependency com.google.cloud:google-cloud-storage to v2.1.4 (#669) - deps: update dependency com.google.cloud:google-cloud-storage to v2.1.5 (#673) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.2.2 (#665) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.8.3 (#678) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.2.3 (#677) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.2.4 (#681) - deps: update dependency com.google.cloud:google-cloud-storage to v2.1.6 (#683) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.8.4 (#682) - deps: update dependency com.google.cloud:google-cloud-storage to v2.1.7 (#689) - deps: update dependency com.google.cloud:google-cloud-storage to v2.1.8 (#696) - deps: update dependency com.google.cloud:google-cloud-storage to v2.1.9 (#698) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.3.0 (#702) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.9.0 (#703) - deps: update dependency com.google.code.gson:gson to v2.8.9 (#707) - deps: update dependency com.google.cloud:google-cloud-storage to v2.2.0 (#710) - deps: update dependency com.google.cloud:google-cloud-storage to v2.2.1 (#722) - docs: Added evalId comment to samples (#727) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.10.0 (#733) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.4.0 (#732) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.11.0 (#740) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.5.0 (#739) - deps: update dependency com.google.cloud:google-cloud-storage to v2.2.2 (#747) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.11.2 (#744) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.5.2 (#748) - chore(deps): update dependency com.google.cloud.samples:shared-configuration to v1.0.24 (#734) - chore(deps): update dependency com.google.cloud.samples:shared-configuration to v1.2.0 (#749) - test: Add null check in teardown (#752) - deps: update dependency com.google.cloud:google-cloud-storage to v2.2.3 (#764) - deps: update dependency com.google.cloud:google-cloud-storage to v2.3.0 (#773) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.11.3 (#762) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.5.3 (#761) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.6.0 (#784) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.12.0 (#782) - deps: update dependency com.google.code.gson:gson to v2.9.0 (#792) - deps: update dependency com.google.cloud:google-cloud-storage to v2.4.0 (#783) - deps: update dependency com.google.cloud:google-cloud-storage to v2.4.4 (#801) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.7.0 (#807) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.13.0 (#808) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.7.1 (#813) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.13.1 (#812) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.7.2 (#819) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.13.2 (#817) - deps: update dependency com.google.cloud:google-cloud-storage to v2.4.5 (#818) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.7.3 (#822) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.13.3 (#823) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.7.4 (#828) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.13.4 (#829) - deps: update dependency com.google.cloud:google-cloud-storage to v2.5.0 (#834) - deps: update dependency com.google.cloud:google-cloud-storage to v2.5.1 (#835) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.8.0 (#838) - deps: update dependency com.google.cloud:google-cloud-storage to v2.6.0 (#840) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.14.0 (#839) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.8.1 (#846) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.14.1 (#847) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.14.2 (#852) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.8.2 (#851) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.8.3 (#855) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.14.3 (#856) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.14.4 (#860) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.8.4 (#859) - deps: update dependency com.google.cloud:google-cloud-storage to v2.6.1 (#863) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.8.5 (#868) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.14.5 (#869) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.14.6 (#875) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.8.6 (#874) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.8.7 (#878) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.14.7 (#879) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.8.8 (#882) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.14.8 (#883) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.14.9 (#890) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.8.9 (#889) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.15.0 (#915) - deps: update dependency com.google.cloud:google-cloud-storage to v2.7.0 (#916) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.9.0 (#914) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.9.1 (#919) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.15.1 (#920) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.15.2 (#924) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.9.2 (#923) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.9.3 (#927) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.15.3 (#928) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.15.4 (#932) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.9.4 (#931) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.15.5 (#936) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.9.5 (#935) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.9.6 (#941) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.15.6 (#942) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v2.9.7 (#953) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.15.7 (#954) - feat(samples): add create-featurestore sample (#948) - feat(samples): added all entity type samples (#976) - feat(samples): add remaining featurestore api samples (#974) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v3 (#986) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.17.0 (#1003) - deps: update dependency com.google.code.gson:gson to v2.9.1 (#1001) - deps: update dependency com.google.cloud:google-cloud-storage to v2.10.0 (#1004) - feat(samples): add all feature samples (#980) - deps: update dependency com.google.cloud:google-cloud-storage to v2.11.0 (#1005) - feat(samples): add all feature values samples (#981) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.14.1 (#1006) - deps: update dependency com.google.cloud:google-cloud-storage to v2.11.1 (#1008) - deps: update dependency com.google.cloud:google-cloud-storage to v2.11.2 (#1010) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.14.3 (#1009) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v3.2.0 (#1020) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.18.0 (#1021) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.14.5 (#1016) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.14.6 (#1026) - deps: update dependency com.google.cloud:google-cloud-storage to v2.11.3 (#1015) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.14.7 (#1031) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.15.0 (#1040) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.16.0 (#1044) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.19.0 (#1051) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v3.3.0 (#1050) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.16.1 (#1046) - deps: update dependency com.google.cloud:google-cloud-storage to v2.12.0 (#1047) - feat(sample): featurestore node updates (#1028) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v3.4.0 (#1085) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.17.0 (#1082) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.20.0 (#1086) - deps: update dependency com.google.cloud:google-cloud-storage to v2.13.0 (#1087) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.17.1 (#1092) - chore(deps): update dependency com.google.cloud:google-cloud-aiplatform to v3.4.1 (#1090) - deps: update dependency com.google.api.grpc:proto-google-cloud-aiplatform-v1beta1 to v0.20.1 (#1091) - deps: update dependency com.google.cloud:google-cloud-bigquery to v2.18.0 (#1113) Fixes #issue > It's a good idea to open an issue first for discussion. - [ ] I have followed [Sample Format Guide](https://togithub.com/GoogleCloudPlatform/java-docs-samples/blob/main/SAMPLE_FORMAT.md) - [ ] `pom.xml` parent set to latest `shared-configuration` - [ ] Appropriate changes to README are included in PR - [ ] API's need to be enabled to test (tell us) - [ ] Environment Variables need to be set (ask us to set them) - [ ] **Tests** pass: `mvn clean verify` **required** - [ ] **Lint** passes: `mvn -P lint checkstyle:check` **required** - [ ] **Static Analysis**: `mvn -P lint clean compile pmd:cpd-check spotbugs:check` **advisory only** - [ ] Please **merge** this PR for me once it is approved. --- aiplatform/pom.xml | 71 ++++ aiplatform/resources/daisy.jpg | Bin 0 -> 76076 bytes aiplatform/resources/image_flower_daisy.jpg | Bin 0 -> 117247 bytes aiplatform/resources/iod_caprese_salad.jpg | Bin 0 -> 450488 bytes .../aiplatform/BatchCreateFeaturesSample.java | 128 +++++++ .../BatchReadFeatureValuesSample.java | 135 +++++++ .../CancelBatchPredictionJobSample.java | 56 +++ .../CancelDataLabelingJobSample.java | 53 +++ .../CancelTrainingPipelineSample.java | 57 +++ ...reateBatchPredictionJobBigquerySample.java | 107 ++++++ .../CreateBatchPredictionJobSample.java | 121 ++++++ ...PredictionJobTextClassificationSample.java | 94 +++++ ...edictionJobTextEntityExtractionSample.java | 95 +++++ ...dictionJobTextSentimentAnalysisSample.java | 94 +++++ ...ictionJobVideoActionRecognitionSample.java | 94 +++++ ...redictionJobVideoClassificationSample.java | 204 +++++++++++ ...redictionJobVideoObjectTrackingSample.java | 201 ++++++++++ ...teDataLabelingJobActiveLearningSample.java | 97 +++++ .../CreateDataLabelingJobImageSample.java | 115 ++++++ .../CreateDataLabelingJobSample.java | 117 ++++++ ...teDataLabelingJobSpecialistPoolSample.java | 104 ++++++ .../CreateDataLabelingJobVideoSample.java | 115 ++++++ .../aiplatform/CreateDatasetImageSample.java | 81 ++++ .../java/aiplatform/CreateDatasetSample.java | 81 ++++ .../CreateDatasetTabularBigquerySample.java | 89 +++++ .../CreateDatasetTabularGcsSample.java | 88 +++++ .../aiplatform/CreateDatasetTextSample.java | 84 +++++ .../aiplatform/CreateDatasetVideoSample.java | 81 ++++ .../java/aiplatform/CreateEndpointSample.java | 74 ++++ .../CreateEntityTypeMonitoringSample.java | 114 ++++++ .../aiplatform/CreateEntityTypeSample.java | 93 +++++ .../java/aiplatform/CreateFeatureSample.java | 108 ++++++ .../CreateFeaturestoreFixedNodesSample.java | 95 +++++ .../aiplatform/CreateFeaturestoreSample.java | 101 +++++ ...parameterTuningJobPythonPackageSample.java | 174 +++++++++ .../CreateHyperparameterTuningJobSample.java | 106 ++++++ ...CreateTrainingPipelineCustomJobSample.java | 119 ++++++ ...ineCustomTrainingManagedDatasetSample.java | 145 ++++++++ ...ningPipelineImageClassificationSample.java | 210 +++++++++++ ...ingPipelineImageObjectDetectionSample.java | 210 +++++++++++ .../CreateTrainingPipelineSample.java | 210 +++++++++++ ...ngPipelineTabularClassificationSample.java | 249 +++++++++++++ ...ainingPipelineTabularRegressionSample.java | 321 ++++++++++++++++ ...iningPipelineTextClassificationSample.java | 209 +++++++++++ ...ingPipelineTextEntityExtractionSample.java | 205 +++++++++++ ...ngPipelineTextSentimentAnalysisSample.java | 213 +++++++++++ ...gPipelineVideoActionRecognitionSample.java | 80 ++++ ...ningPipelineVideoClassificationSample.java | 160 ++++++++ ...ningPipelineVideoObjectTrackingSample.java | 172 +++++++++ .../DeleteBatchPredictionJobSample.java | 68 ++++ .../DeleteDataLabelingJobSample.java | 67 ++++ .../java/aiplatform/DeleteDatasetSample.java | 67 ++++ .../java/aiplatform/DeleteEndpointSample.java | 67 ++++ .../aiplatform/DeleteEntityTypeSample.java | 87 +++++ .../aiplatform/DeleteExportModelSample.java | 45 +++ .../java/aiplatform/DeleteFeatureSample.java | 90 +++++ .../aiplatform/DeleteFeaturestoreSample.java | 86 +++++ .../java/aiplatform/DeleteModelSample.java | 63 ++++ .../DeleteTrainingPipelineSample.java | 68 ++++ .../DeployModelCustomTrainedModelSample.java | 92 +++++ .../java/aiplatform/DeployModelSample.java | 113 ++++++ .../aiplatform/ExportFeatureValuesSample.java | 119 ++++++ .../ExportFeatureValuesSnapshotSample.java | 119 ++++++ .../java/aiplatform/ExportModelSample.java | 81 ++++ ...xportModelTabularClassificationSample.java | 79 ++++ ...portModelVideoActionRecognitionSample.java | 79 ++++ .../GetBatchPredictionJobSample.java | 135 +++++++ .../java/aiplatform/GetEntityTypeSample.java | 70 ++++ .../java/aiplatform/GetFeatureSample.java | 79 ++++ .../aiplatform/GetFeaturestoreSample.java | 67 ++++ .../GetHyperparameterTuningJobSample.java | 55 +++ ...elEvaluationImageClassificationSample.java | 76 ++++ ...lEvaluationImageObjectDetectionSample.java | 76 ++++ .../aiplatform/GetModelEvaluationSample.java | 63 ++++ .../GetModelEvaluationSliceSample.java | 82 +++++ ...EvaluationTabularClassificationSample.java | 75 ++++ ...odelEvaluationTabularRegressionSample.java | 75 ++++ ...delEvaluationTextClassificationSample.java | 77 ++++ ...lEvaluationTextEntityExtractionSample.java | 77 ++++ ...EvaluationTextSentimentAnalysisSample.java | 77 ++++ ...valuationVideoActionRecognitionSample.java | 68 ++++ ...elEvaluationVideoClassificationSample.java | 76 ++++ ...elEvaluationVideoObjectTrackingSample.java | 76 ++++ .../main/java/aiplatform/GetModelSample.java | 120 ++++++ .../aiplatform/GetTrainingPipelineSample.java | 177 +++++++++ .../ImportDataImageClassificationSample.java | 89 +++++ .../ImportDataImageObjectDetectionSample.java | 88 +++++ ...taTextClassificationSingleLabelSample.java | 90 +++++ .../ImportDataTextEntityExtractionSample.java | 89 +++++ ...ImportDataTextSentimentAnalysisSample.java | 90 +++++ ...mportDataVideoActionRecognitionSample.java | 82 +++++ .../ImportDataVideoClassificationSample.java | 88 +++++ .../ImportDataVideoObjectTrackingSample.java | 86 +++++ .../aiplatform/ImportFeatureValuesSample.java | 122 +++++++ .../ListEntityTypesAsyncSample.java | 80 ++++ .../aiplatform/ListEntityTypesSample.java | 68 ++++ .../aiplatform/ListFeaturesAsyncSample.java | 83 +++++ .../java/aiplatform/ListFeaturesSample.java | 72 ++++ .../ListFeaturestoresAsyncSample.java | 78 ++++ .../aiplatform/ListFeaturestoresSample.java | 67 ++++ .../ListModelEvaluationSliceSample.java | 80 ++++ .../PredictCustomTrainedModelSample.java | 76 ++++ .../PredictImageClassificationSample.java | 104 ++++++ .../PredictImageObjectDetectionSample.java | 103 ++++++ .../PredictTabularClassificationSample.java | 84 +++++ .../PredictTabularRegressionSample.java | 83 +++++ ...ctTextClassificationSingleLabelSample.java | 90 +++++ .../PredictTextEntityExtractionSample.java | 94 +++++ .../PredictTextSentimentAnalysisSample.java | 78 ++++ .../aiplatform/SearchFeaturesAsyncSample.java | 81 ++++ .../java/aiplatform/SearchFeaturesSample.java | 69 ++++ .../java/aiplatform/UndeployModelSample.java | 79 ++++ .../UpdateEntityTypeMonitoringSample.java | 87 +++++ .../aiplatform/UpdateEntityTypeSample.java | 80 ++++ .../java/aiplatform/UpdateFeatureSample.java | 79 ++++ .../UpdateFeaturestoreFixedNodesSample.java | 93 +++++ .../aiplatform/UpdateFeaturestoreSample.java | 98 +++++ .../java/aiplatform/UploadModelSample.java | 89 +++++ .../CancelDataLabelingJobSampleTest.java | 110 ++++++ .../CancelTrainingPipelineSampleTest.java | 123 +++++++ ...eBatchPredictionJobBigquerySampleTest.java | 109 ++++++ .../CreateBatchPredictionJobSampleTest.java | 109 ++++++ ...ictionJobTextClassificationSampleTest.java | 115 ++++++ ...tionJobTextEntityExtractionSampleTest.java | 113 ++++++ ...ionJobTextSentimentAnalysisSampleTest.java | 113 ++++++ ...onJobVideoActionRecognitionSampleTest.java | 107 ++++++ ...ctionJobVideoClassificationSampleTest.java | 111 ++++++ ...ctionJobVideoObjectTrackingSampleTest.java | 110 ++++++ ...taLabelingJobActiveLearningSampleTest.java | 115 ++++++ .../CreateDataLabelingJobImageSampleTest.java | 107 ++++++ .../CreateDataLabelingJobSampleTest.java | 114 ++++++ ...taLabelingJobSpecialistPoolSampleTest.java | 118 ++++++ .../CreateDataLabelingJobVideoSampleTest.java | 107 ++++++ .../CreateDatasetImageSampleTest.java | 96 +++++ .../aiplatform/CreateDatasetSampleTest.java | 96 +++++ ...reateDatasetTabularBigquerySampleTest.java | 93 +++++ .../CreateDatasetTabularGcsSampleTest.java | 95 +++++ .../CreateDatasetTextSampleTest.java | 96 +++++ .../CreateDatasetVideoSampleTest.java | 97 +++++ .../aiplatform/CreateEndpointSampleTest.java | 94 +++++ ...meterTuningJobPythonPackageSampleTest.java | 118 ++++++ ...eateHyperparameterTuningJobSampleTest.java | 106 ++++++ ...teTrainingPipelineCustomJobSampleTest.java | 128 +++++++ ...ustomTrainingManagedDatasetSampleTest.java | 121 ++++++ ...PipelineImageClassificationSampleTest.java | 113 ++++++ ...ipelineImageObjectDetectionSampleTest.java | 109 ++++++ .../CreateTrainingPipelineSampleTest.java | 113 ++++++ ...pelineTabularClassificationSampleTest.java | 126 +++++++ ...ngPipelineTabularRegressionSampleTest.java | 106 ++++++ ...gPipelineTextClassificationSampleTest.java | 110 ++++++ ...ipelineTextEntityExtractionSampleTest.java | 114 ++++++ ...pelineTextSentimentAnalysisSampleTest.java | 110 ++++++ ...elineVideoActionRecognitionSampleTest.java | 108 ++++++ ...PipelineVideoClassificationSampleTest.java | 110 ++++++ ...PipelineVideoObjectTrackingSampleTest.java | 110 ++++++ ...ployModelCustomTrainedModelSampleTest.java | 97 +++++ .../aiplatform/DeployModelSampleTest.java | 87 +++++ .../aiplatform/ExportModelSampleTest.java | 94 +++++ ...tModelTabularClassificationSampleTest.java | 89 +++++ ...ModelVideoActionRecognitionSampleTest.java | 91 +++++ .../aiplatform/FeatureValuesSamplesTest.java | 345 ++++++++++++++++++ .../aiplatform/FeaturestoreSamplesTest.java | 220 +++++++++++ .../GetHyperparameterTuningJobSampleTest.java | 73 ++++ ...aluationImageClassificationSampleTest.java | 79 ++++ ...luationImageObjectDetectionSampleTest.java | 79 ++++ .../GetModelEvaluationSampleTest.java | 78 ++++ .../GetModelEvaluationSliceSampleTest.java | 80 ++++ ...uationTabularClassificationSampleTest.java | 76 ++++ ...EvaluationTabularRegressionSampleTest.java | 76 ++++ ...valuationTextClassificationSampleTest.java | 79 ++++ ...luationTextEntityExtractionSampleTest.java | 79 ++++ ...uationTextSentimentAnalysisSampleTest.java | 79 ++++ ...ationVideoActionRecognitionSampleTest.java | 77 ++++ ...aluationVideoClassificationSampleTest.java | 76 ++++ ...aluationVideoObjectTrackingSampleTest.java | 76 ++++ .../java/aiplatform/GetModelSampleTest.java | 77 ++++ .../GetTrainingPipelineSampleTest.java | 75 ++++ ...portDataImageClassificationSampleTest.java | 133 +++++++ ...ortDataImageObjectDetectionSampleTest.java | 133 +++++++ .../java/aiplatform/ImportDataSampleTest.java | 89 +++++ ...tDataVideoActionRecognitionSampleTest.java | 130 +++++++ ...portDataVideoClassificationSampleTest.java | 131 +++++++ ...portDataVideoObjectTrackingSampleTest.java | 130 +++++++ .../ListModelEvaluationSliceSampleTest.java | 79 ++++ .../PredictCustomTrainedModelSampleTest.java | 82 +++++ .../PredictImageClassificationSampleTest.java | 75 ++++ ...PredictImageObjectDetectionSampleTest.java | 77 ++++ ...redictTabularClassificationSampleTest.java | 81 ++++ .../PredictTabularRegressionSampleTest.java | 100 +++++ ...xtClassificationSingleLabelSampleTest.java | 76 ++++ ...PredictTextEntityExtractionSampleTest.java | 88 +++++ ...redictTextSentimentAnalysisSampleTest.java | 89 +++++ .../aiplatform/UploadModelSampleTest.java | 98 +++++ 193 files changed, 19563 insertions(+) create mode 100644 aiplatform/pom.xml create mode 100644 aiplatform/resources/daisy.jpg create mode 100644 aiplatform/resources/image_flower_daisy.jpg create mode 100644 aiplatform/resources/iod_caprese_salad.jpg create mode 100644 aiplatform/src/main/java/aiplatform/BatchCreateFeaturesSample.java create mode 100644 aiplatform/src/main/java/aiplatform/BatchReadFeatureValuesSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CancelBatchPredictionJobSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CancelDataLabelingJobSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CancelTrainingPipelineSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobBigquerySample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextEntityExtractionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextSentimentAnalysisSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoActionRecognitionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoObjectTrackingSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDataLabelingJobActiveLearningSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDataLabelingJobImageSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDataLabelingJobSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDataLabelingJobSpecialistPoolSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDataLabelingJobVideoSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDatasetImageSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDatasetSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDatasetTabularBigquerySample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDatasetTabularGcsSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDatasetTextSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateDatasetVideoSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateEndpointSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateEntityTypeMonitoringSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateEntityTypeSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateFeatureSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateFeaturestoreFixedNodesSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateFeaturestoreSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateHyperparameterTuningJobPythonPackageSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateHyperparameterTuningJobSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineCustomJobSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineCustomTrainingManagedDatasetSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineImageClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineImageObjectDetectionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTabularClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTabularRegressionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextEntityExtractionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextSentimentAnalysisSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoActionRecognitionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoObjectTrackingSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeleteBatchPredictionJobSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeleteDataLabelingJobSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeleteDatasetSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeleteEndpointSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeleteEntityTypeSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeleteExportModelSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeleteFeatureSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeleteFeaturestoreSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeleteModelSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeleteTrainingPipelineSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeployModelCustomTrainedModelSample.java create mode 100644 aiplatform/src/main/java/aiplatform/DeployModelSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ExportFeatureValuesSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ExportFeatureValuesSnapshotSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ExportModelSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ExportModelTabularClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ExportModelVideoActionRecognitionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetBatchPredictionJobSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetEntityTypeSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetFeatureSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetFeaturestoreSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetHyperparameterTuningJobSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationImageClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationImageObjectDetectionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationSliceSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationTabularClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationTabularRegressionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationTextClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationTextEntityExtractionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationTextSentimentAnalysisSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoActionRecognitionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoObjectTrackingSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetModelSample.java create mode 100644 aiplatform/src/main/java/aiplatform/GetTrainingPipelineSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ImportDataImageClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ImportDataImageObjectDetectionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ImportDataTextClassificationSingleLabelSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ImportDataTextEntityExtractionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ImportDataTextSentimentAnalysisSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ImportDataVideoActionRecognitionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ImportDataVideoClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ImportDataVideoObjectTrackingSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ImportFeatureValuesSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ListEntityTypesAsyncSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ListEntityTypesSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ListFeaturesAsyncSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ListFeaturesSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ListFeaturestoresAsyncSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ListFeaturestoresSample.java create mode 100644 aiplatform/src/main/java/aiplatform/ListModelEvaluationSliceSample.java create mode 100644 aiplatform/src/main/java/aiplatform/PredictCustomTrainedModelSample.java create mode 100644 aiplatform/src/main/java/aiplatform/PredictImageClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/PredictImageObjectDetectionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/PredictTabularClassificationSample.java create mode 100644 aiplatform/src/main/java/aiplatform/PredictTabularRegressionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/PredictTextClassificationSingleLabelSample.java create mode 100644 aiplatform/src/main/java/aiplatform/PredictTextEntityExtractionSample.java create mode 100644 aiplatform/src/main/java/aiplatform/PredictTextSentimentAnalysisSample.java create mode 100644 aiplatform/src/main/java/aiplatform/SearchFeaturesAsyncSample.java create mode 100644 aiplatform/src/main/java/aiplatform/SearchFeaturesSample.java create mode 100644 aiplatform/src/main/java/aiplatform/UndeployModelSample.java create mode 100644 aiplatform/src/main/java/aiplatform/UpdateEntityTypeMonitoringSample.java create mode 100644 aiplatform/src/main/java/aiplatform/UpdateEntityTypeSample.java create mode 100644 aiplatform/src/main/java/aiplatform/UpdateFeatureSample.java create mode 100644 aiplatform/src/main/java/aiplatform/UpdateFeaturestoreFixedNodesSample.java create mode 100644 aiplatform/src/main/java/aiplatform/UpdateFeaturestoreSample.java create mode 100644 aiplatform/src/main/java/aiplatform/UploadModelSample.java create mode 100644 aiplatform/src/test/java/aiplatform/CancelDataLabelingJobSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CancelTrainingPipelineSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobBigquerySampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextEntityExtractionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextSentimentAnalysisSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoActionRecognitionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoObjectTrackingSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDataLabelingJobActiveLearningSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDataLabelingJobImageSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDataLabelingJobSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDataLabelingJobSpecialistPoolSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDataLabelingJobVideoSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDatasetImageSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDatasetSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDatasetTabularBigquerySampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDatasetTabularGcsSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDatasetTextSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateDatasetVideoSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateEndpointSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateHyperparameterTuningJobPythonPackageSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateHyperparameterTuningJobSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineCustomJobSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineCustomTrainingManagedDatasetSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineImageClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineImageObjectDetectionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTabularClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTabularRegressionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextEntityExtractionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextSentimentAnalysisSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoActionRecognitionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoObjectTrackingSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/DeployModelCustomTrainedModelSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/DeployModelSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/ExportModelSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/ExportModelTabularClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/ExportModelVideoActionRecognitionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/FeatureValuesSamplesTest.java create mode 100644 aiplatform/src/test/java/aiplatform/FeaturestoreSamplesTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetHyperparameterTuningJobSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationImageClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationImageObjectDetectionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationSliceSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationTabularClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationTabularRegressionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationTextClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationTextEntityExtractionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationTextSentimentAnalysisSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoActionRecognitionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoObjectTrackingSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetModelSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/GetTrainingPipelineSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/ImportDataImageClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/ImportDataImageObjectDetectionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/ImportDataSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/ImportDataVideoActionRecognitionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/ImportDataVideoClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/ImportDataVideoObjectTrackingSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/ListModelEvaluationSliceSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/PredictCustomTrainedModelSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/PredictImageClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/PredictImageObjectDetectionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/PredictTabularClassificationSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/PredictTabularRegressionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/PredictTextClassificationSingleLabelSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/PredictTextEntityExtractionSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/PredictTextSentimentAnalysisSampleTest.java create mode 100644 aiplatform/src/test/java/aiplatform/UploadModelSampleTest.java diff --git a/aiplatform/pom.xml b/aiplatform/pom.xml new file mode 100644 index 00000000000..0ba47527ea9 --- /dev/null +++ b/aiplatform/pom.xml @@ -0,0 +1,71 @@ + + + 4.0.0 + com.example.aiplatform + aiplatform-snippets + jar + Google Cloud Vertex AI Snippets + https://github.com/GoogleCloudPlatform/java-docs-samples/tree/main/aiplatform + + + + com.google.cloud.samples + shared-configuration + 1.2.0 + + + + 1.8 + 1.8 + UTF-8 + + + + + com.google.cloud + google-cloud-aiplatform + 3.4.1 + + + + com.google.cloud + google-cloud-storage + 2.13.0 + + + com.google.protobuf + protobuf-java-util + 4.0.0-rc-2 + + + com.google.code.gson + gson + 2.9.1 + + + junit + junit + 4.13.2 + test + + + com.google.truth + truth + 1.1.3 + test + + + com.google.api.grpc + proto-google-cloud-aiplatform-v1beta1 + 0.20.1 + + + com.google.cloud + google-cloud-bigquery + 2.18.0 + + + diff --git a/aiplatform/resources/daisy.jpg b/aiplatform/resources/daisy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ae01cae918365637aa3ac44bfb052fb86a964441 GIT binary patch literal 76076 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

P&A^o`)gR|ea8V&AzxH`){L&td}kdoe;WRl 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 Z_k--s^M)thNP6J(pJM)R=kW2z|Jl>KiNpW^ literal 0 HcmV?d00001 diff --git a/aiplatform/resources/image_flower_daisy.jpg b/aiplatform/resources/image_flower_daisy.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3ba1d67705ac853285fd3c9ce6cfa2838c495d84 GIT binary patch literal 117247 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%0D@ZJ={lk|>x-&%KIe#_ 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

%YQtf_iJ+)xT! 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 Gum9P23%c(B literal 0 HcmV?d00001 diff --git a/aiplatform/resources/iod_caprese_salad.jpg b/aiplatform/resources/iod_caprese_salad.jpg new file mode 100644 index 0000000000000000000000000000000000000000..100ad677a9125e9d878effceb96dd3794dce9a2b GIT binary patch literal 450488 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

fU( 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μNcxJHjyvGv?$z8{gBL>czD|Q#)?6l+Vo? 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 createFeatureRequests = new ArrayList<>(); + + Feature titleFeature = + Feature.newBuilder() + .setDescription("The title of the movie") + .setValueType(ValueType.STRING) + .build(); + Feature genresFeature = + Feature.newBuilder() + .setDescription("The genres of the movie") + .setValueType(ValueType.STRING) + .build(); + Feature averageRatingFeature = + Feature.newBuilder() + .setDescription("The average rating for the movie, range is [1.0-5.0]") + .setValueType(ValueType.DOUBLE) + .build(); + + createFeatureRequests.add( + CreateFeatureRequest.newBuilder().setFeature(titleFeature).setFeatureId("title").build()); + + createFeatureRequests.add( + CreateFeatureRequest.newBuilder() + .setFeature(genresFeature) + .setFeatureId("genres") + .build()); + + createFeatureRequests.add( + CreateFeatureRequest.newBuilder() + .setFeature(averageRatingFeature) + .setFeatureId("average_rating") + .build()); + + BatchCreateFeaturesRequest batchCreateFeaturesRequest = + BatchCreateFeaturesRequest.newBuilder() + .setParent( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .addAllRequests(createFeatureRequests) + .build(); + + OperationFuture + batchCreateFeaturesFuture = + featurestoreServiceClient.batchCreateFeaturesAsync(batchCreateFeaturesRequest); + System.out.format( + "Operation name: %s%n", batchCreateFeaturesFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + BatchCreateFeaturesResponse batchCreateFeaturesResponse = + batchCreateFeaturesFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Batch Create Features Response"); + System.out.println(batchCreateFeaturesResponse); + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_batch_create_features_sample] diff --git a/aiplatform/src/main/java/aiplatform/BatchReadFeatureValuesSample.java b/aiplatform/src/main/java/aiplatform/BatchReadFeatureValuesSample.java new file mode 100644 index 00000000000..a76c3388d1e --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/BatchReadFeatureValuesSample.java @@ -0,0 +1,135 @@ +/* + * 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. + * + * + * Batch read feature values from a featurestore, as determined by your + * read instances list file, to export data. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_batch_read_feature_values_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.BatchReadFeatureValuesOperationMetadata; +import com.google.cloud.aiplatform.v1.BatchReadFeatureValuesRequest; +import com.google.cloud.aiplatform.v1.BatchReadFeatureValuesRequest.EntityTypeSpec; +import com.google.cloud.aiplatform.v1.BatchReadFeatureValuesResponse; +import com.google.cloud.aiplatform.v1.BigQueryDestination; +import com.google.cloud.aiplatform.v1.CsvSource; +import com.google.cloud.aiplatform.v1.FeatureSelector; +import com.google.cloud.aiplatform.v1.FeatureValueDestination; +import com.google.cloud.aiplatform.v1.FeaturestoreName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.IdMatcher; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class BatchReadFeatureValuesSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String inputCsvFile = "YOU_INPUT_CSV_FILE"; + String destinationTableUri = "YOUR_DESTINATION_TABLE_URI"; + List featureSelectorIds = Arrays.asList("title", "genres", "average_rating"); + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 300; + batchReadFeatureValuesSample( + project, + featurestoreId, + entityTypeId, + inputCsvFile, + destinationTableUri, + featureSelectorIds, + location, + endpoint, + timeout); + } + + static void batchReadFeatureValuesSample( + String project, + String featurestoreId, + String entityTypeId, + String inputCsvFile, + String destinationTableUri, + List featureSelectorIds, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + List entityTypeSpecs = new ArrayList<>(); + + FeatureSelector featureSelector = + FeatureSelector.newBuilder() + .setIdMatcher(IdMatcher.newBuilder().addAllIds(featureSelectorIds).build()) + .build(); + EntityTypeSpec entityTypeSpec = + EntityTypeSpec.newBuilder() + .setEntityTypeId(entityTypeId) + .setFeatureSelector(featureSelector) + .build(); + + entityTypeSpecs.add(entityTypeSpec); + + BigQueryDestination bigQueryDestination = + BigQueryDestination.newBuilder().setOutputUri(destinationTableUri).build(); + GcsSource gcsSource = GcsSource.newBuilder().addUris(inputCsvFile).build(); + BatchReadFeatureValuesRequest batchReadFeatureValuesRequest = + BatchReadFeatureValuesRequest.newBuilder() + .setFeaturestore(FeaturestoreName.of(project, location, featurestoreId).toString()) + .setCsvReadInstances(CsvSource.newBuilder().setGcsSource(gcsSource)) + .setDestination( + FeatureValueDestination.newBuilder().setBigqueryDestination(bigQueryDestination)) + .addAllEntityTypeSpecs(entityTypeSpecs) + .build(); + + OperationFuture + batchReadFeatureValuesFuture = + featurestoreServiceClient.batchReadFeatureValuesAsync(batchReadFeatureValuesRequest); + System.out.format( + "Operation name: %s%n", batchReadFeatureValuesFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + BatchReadFeatureValuesResponse batchReadFeatureValuesResponse = + batchReadFeatureValuesFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Batch Read Feature Values Response"); + System.out.println(batchReadFeatureValuesResponse); + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_batch_read_feature_values_sample] diff --git a/aiplatform/src/main/java/aiplatform/CancelBatchPredictionJobSample.java b/aiplatform/src/main/java/aiplatform/CancelBatchPredictionJobSample.java new file mode 100644 index 00000000000..495f0f88598 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CancelBatchPredictionJobSample.java @@ -0,0 +1,56 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_cancel_batch_prediction_job_sample] + +import com.google.cloud.aiplatform.v1.BatchPredictionJobName; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import java.io.IOException; + +public class CancelBatchPredictionJobSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String batchPredictionJobId = "YOUR_BATCH_PREDICTION_JOB_ID"; + cancelBatchPredictionJobSample(project, batchPredictionJobId); + } + + static void cancelBatchPredictionJobSample(String project, String batchPredictionJobId) + throws IOException { + JobServiceSettings jobServiceSettings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient jobServiceClient = JobServiceClient.create(jobServiceSettings)) { + String location = "us-central1"; + BatchPredictionJobName batchPredictionJobName = + BatchPredictionJobName.of(project, location, batchPredictionJobId); + + jobServiceClient.cancelBatchPredictionJob(batchPredictionJobName); + + System.out.println("Cancelled the Batch Prediction Job"); + } + } +} +// [END aiplatform_cancel_batch_prediction_job_sample] diff --git a/aiplatform/src/main/java/aiplatform/CancelDataLabelingJobSample.java b/aiplatform/src/main/java/aiplatform/CancelDataLabelingJobSample.java new file mode 100644 index 00000000000..eb540687edf --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CancelDataLabelingJobSample.java @@ -0,0 +1,53 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_cancel_data_labeling_job_sample] + +import com.google.cloud.aiplatform.v1.DataLabelingJobName; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import java.io.IOException; + +public class CancelDataLabelingJobSample { + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String dataLabelingJobId = "YOUR_DATA_LABELING_JOB_ID"; + cancelDataLabelingJob(project, dataLabelingJobId); + } + + static void cancelDataLabelingJob(String project, String dataLabelingJobId) throws IOException { + JobServiceSettings jobServiceSettings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient jobServiceClient = JobServiceClient.create(jobServiceSettings)) { + String location = "us-central1"; + + DataLabelingJobName dataLabelingJobName = + DataLabelingJobName.of(project, location, dataLabelingJobId); + jobServiceClient.cancelDataLabelingJob(dataLabelingJobName); + System.out.println("Cancelled Data labeling job"); + } + } +} +// [END aiplatform_cancel_data_labeling_job_sample] diff --git a/aiplatform/src/main/java/aiplatform/CancelTrainingPipelineSample.java b/aiplatform/src/main/java/aiplatform/CancelTrainingPipelineSample.java new file mode 100644 index 00000000000..a689ae24625 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CancelTrainingPipelineSample.java @@ -0,0 +1,57 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_cancel_training_pipeline_sample] + +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.TrainingPipelineName; +import java.io.IOException; + +public class CancelTrainingPipelineSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String trainingPipelineId = "YOUR_TRAINING_PIPELINE_ID"; + String project = "YOUR_PROJECT_ID"; + cancelTrainingPipelineSample(project, trainingPipelineId); + } + + static void cancelTrainingPipelineSample(String project, String trainingPipelineId) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + TrainingPipelineName trainingPipelineName = + TrainingPipelineName.of(project, location, trainingPipelineId); + + pipelineServiceClient.cancelTrainingPipeline(trainingPipelineName); + + System.out.println("Cancelled the Training Pipeline"); + } + } +} +// [END aiplatform_cancel_training_pipeline_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobBigquerySample.java b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobBigquerySample.java new file mode 100644 index 00000000000..105268f2e8b --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobBigquerySample.java @@ -0,0 +1,107 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_batch_prediction_job_bigquery_sample] +import com.google.cloud.aiplatform.v1.BatchPredictionJob; +import com.google.cloud.aiplatform.v1.BigQueryDestination; +import com.google.cloud.aiplatform.v1.BigQuerySource; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.gson.JsonObject; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; + +public class CreateBatchPredictionJobBigquerySample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String displayName = "DISPLAY_NAME"; + String modelName = "MODEL_NAME"; + String instancesFormat = "INSTANCES_FORMAT"; + String bigquerySourceInputUri = "BIGQUERY_SOURCE_INPUT_URI"; + String predictionsFormat = "PREDICTIONS_FORMAT"; + String bigqueryDestinationOutputUri = "BIGQUERY_DESTINATION_OUTPUT_URI"; + createBatchPredictionJobBigquerySample( + project, + displayName, + modelName, + instancesFormat, + bigquerySourceInputUri, + predictionsFormat, + bigqueryDestinationOutputUri); + } + + static void createBatchPredictionJobBigquerySample( + String project, + String displayName, + String model, + String instancesFormat, + String bigquerySourceInputUri, + String predictionsFormat, + String bigqueryDestinationOutputUri) + throws IOException { + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + JsonObject jsonModelParameters = new JsonObject(); + Value.Builder modelParametersBuilder = Value.newBuilder(); + JsonFormat.parser().merge(jsonModelParameters.toString(), modelParametersBuilder); + Value modelParameters = modelParametersBuilder.build(); + BigQuerySource bigquerySource = + BigQuerySource.newBuilder().setInputUri(bigquerySourceInputUri).build(); + BatchPredictionJob.InputConfig inputConfig = + BatchPredictionJob.InputConfig.newBuilder() + .setInstancesFormat(instancesFormat) + .setBigquerySource(bigquerySource) + .build(); + BigQueryDestination bigqueryDestination = + BigQueryDestination.newBuilder().setOutputUri(bigqueryDestinationOutputUri).build(); + BatchPredictionJob.OutputConfig outputConfig = + BatchPredictionJob.OutputConfig.newBuilder() + .setPredictionsFormat(predictionsFormat) + .setBigqueryDestination(bigqueryDestination) + .build(); + String modelName = ModelName.of(project, location, model).toString(); + BatchPredictionJob batchPredictionJob = + BatchPredictionJob.newBuilder() + .setDisplayName(displayName) + .setModel(modelName) + .setModelParameters(modelParameters) + .setInputConfig(inputConfig) + .setOutputConfig(outputConfig) + .build(); + LocationName parent = LocationName.of(project, location); + BatchPredictionJob response = client.createBatchPredictionJob(parent, batchPredictionJob); + System.out.format("response: %s\n", response); + System.out.format("\tName: %s\n", response.getName()); + } + } +} + +// [END aiplatform_create_batch_prediction_job_bigquery_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobSample.java b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobSample.java new file mode 100644 index 00000000000..12bab04e13b --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobSample.java @@ -0,0 +1,121 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_batch_prediction_job_sample] +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.AcceleratorType; +import com.google.cloud.aiplatform.v1.BatchDedicatedResources; +import com.google.cloud.aiplatform.v1.BatchPredictionJob; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.MachineSpec; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.protobuf.Value; +import java.io.IOException; + +public class CreateBatchPredictionJobSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String displayName = "DISPLAY_NAME"; + String modelName = "MODEL_NAME"; + String instancesFormat = "INSTANCES_FORMAT"; + String gcsSourceUri = "GCS_SOURCE_URI"; + String predictionsFormat = "PREDICTIONS_FORMAT"; + String gcsDestinationOutputUriPrefix = "GCS_DESTINATION_OUTPUT_URI_PREFIX"; + createBatchPredictionJobSample( + project, + displayName, + modelName, + instancesFormat, + gcsSourceUri, + predictionsFormat, + gcsDestinationOutputUriPrefix); + } + + static void createBatchPredictionJobSample( + String project, + String displayName, + String model, + String instancesFormat, + String gcsSourceUri, + String predictionsFormat, + String gcsDestinationOutputUriPrefix) + throws IOException { + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + + // Passing in an empty Value object for model parameters + Value modelParameters = ValueConverter.EMPTY_VALUE; + + GcsSource gcsSource = GcsSource.newBuilder().addUris(gcsSourceUri).build(); + BatchPredictionJob.InputConfig inputConfig = + BatchPredictionJob.InputConfig.newBuilder() + .setInstancesFormat(instancesFormat) + .setGcsSource(gcsSource) + .build(); + GcsDestination gcsDestination = + GcsDestination.newBuilder().setOutputUriPrefix(gcsDestinationOutputUriPrefix).build(); + BatchPredictionJob.OutputConfig outputConfig = + BatchPredictionJob.OutputConfig.newBuilder() + .setPredictionsFormat(predictionsFormat) + .setGcsDestination(gcsDestination) + .build(); + MachineSpec machineSpec = + MachineSpec.newBuilder() + .setMachineType("n1-standard-2") + .setAcceleratorType(AcceleratorType.NVIDIA_TESLA_K80) + .setAcceleratorCount(1) + .build(); + BatchDedicatedResources dedicatedResources = + BatchDedicatedResources.newBuilder() + .setMachineSpec(machineSpec) + .setStartingReplicaCount(1) + .setMaxReplicaCount(1) + .build(); + String modelName = ModelName.of(project, location, model).toString(); + BatchPredictionJob batchPredictionJob = + BatchPredictionJob.newBuilder() + .setDisplayName(displayName) + .setModel(modelName) + .setModelParameters(modelParameters) + .setInputConfig(inputConfig) + .setOutputConfig(outputConfig) + .setDedicatedResources(dedicatedResources) + .build(); + LocationName parent = LocationName.of(project, location); + BatchPredictionJob response = client.createBatchPredictionJob(parent, batchPredictionJob); + System.out.format("response: %s\n", response); + System.out.format("\tName: %s\n", response.getName()); + } + } +} + +// [END aiplatform_create_batch_prediction_job_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextClassificationSample.java b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextClassificationSample.java new file mode 100644 index 00000000000..ba79bf14b02 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextClassificationSample.java @@ -0,0 +1,94 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_batch_prediction_job_text_classification_sample] +import com.google.api.gax.rpc.ApiException; +import com.google.cloud.aiplatform.v1.BatchPredictionJob; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.ModelName; +import java.io.IOException; + +public class CreateBatchPredictionJobTextClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String location = "us-central1"; + String displayName = "DISPLAY_NAME"; + String modelId = "MODEL_ID"; + String gcsSourceUri = "GCS_SOURCE_URI"; + String gcsDestinationOutputUriPrefix = "GCS_DESTINATION_OUTPUT_URI_PREFIX"; + createBatchPredictionJobTextClassificationSample( + project, location, displayName, modelId, gcsSourceUri, gcsDestinationOutputUriPrefix); + } + + static void createBatchPredictionJobTextClassificationSample( + String project, + String location, + String displayName, + String modelId, + String gcsSourceUri, + String gcsDestinationOutputUriPrefix) + throws IOException { + // The AI Platform services require regional API endpoints. + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + try { + String modelName = ModelName.of(project, location, modelId).toString(); + GcsSource gcsSource = GcsSource.newBuilder().addUris(gcsSourceUri).build(); + BatchPredictionJob.InputConfig inputConfig = + BatchPredictionJob.InputConfig.newBuilder() + .setInstancesFormat("jsonl") + .setGcsSource(gcsSource) + .build(); + GcsDestination gcsDestination = + GcsDestination.newBuilder().setOutputUriPrefix(gcsDestinationOutputUriPrefix).build(); + BatchPredictionJob.OutputConfig outputConfig = + BatchPredictionJob.OutputConfig.newBuilder() + .setPredictionsFormat("jsonl") + .setGcsDestination(gcsDestination) + .build(); + BatchPredictionJob batchPredictionJob = + BatchPredictionJob.newBuilder() + .setDisplayName(displayName) + .setModel(modelName) + .setInputConfig(inputConfig) + .setOutputConfig(outputConfig) + .build(); + LocationName parent = LocationName.of(project, location); + BatchPredictionJob response = client.createBatchPredictionJob(parent, batchPredictionJob); + System.out.format("response: %s\n", response); + } catch (ApiException ex) { + System.out.format("Exception: %s\n", ex.getLocalizedMessage()); + } + } + } +} + +// [END aiplatform_create_batch_prediction_job_text_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextEntityExtractionSample.java b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextEntityExtractionSample.java new file mode 100644 index 00000000000..e753da2ed04 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextEntityExtractionSample.java @@ -0,0 +1,95 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_batch_prediction_job_text_entity_extraction_sample] +import com.google.api.gax.rpc.ApiException; +import com.google.cloud.aiplatform.v1.BatchPredictionJob; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.ModelName; +import java.io.IOException; + +public class CreateBatchPredictionJobTextEntityExtractionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String location = "us-central1"; + String displayName = "DISPLAY_NAME"; + String modelId = "MODEL_ID"; + String gcsSourceUri = "GCS_SOURCE_URI"; + String gcsDestinationOutputUriPrefix = "GCS_DESTINATION_OUTPUT_URI_PREFIX"; + createBatchPredictionJobTextEntityExtractionSample( + project, location, displayName, modelId, gcsSourceUri, gcsDestinationOutputUriPrefix); + } + + static void createBatchPredictionJobTextEntityExtractionSample( + String project, + String location, + String displayName, + String modelId, + String gcsSourceUri, + String gcsDestinationOutputUriPrefix) + throws IOException { + // The AI Platform services require regional API endpoints. + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + try { + String modelName = ModelName.of(project, location, modelId).toString(); + GcsSource gcsSource = GcsSource.newBuilder().addUris(gcsSourceUri).build(); + BatchPredictionJob.InputConfig inputConfig = + BatchPredictionJob.InputConfig.newBuilder() + .setInstancesFormat("jsonl") + .setGcsSource(gcsSource) + .build(); + GcsDestination gcsDestination = + GcsDestination.newBuilder().setOutputUriPrefix(gcsDestinationOutputUriPrefix).build(); + BatchPredictionJob.OutputConfig outputConfig = + BatchPredictionJob.OutputConfig.newBuilder() + .setPredictionsFormat("jsonl") + .setGcsDestination(gcsDestination) + .build(); + BatchPredictionJob batchPredictionJob = + BatchPredictionJob.newBuilder() + .setDisplayName(displayName) + .setModel(modelName) + .setInputConfig(inputConfig) + .setOutputConfig(outputConfig) + .build(); + LocationName parent = LocationName.of(project, location); + BatchPredictionJob response = client.createBatchPredictionJob(parent, batchPredictionJob); + System.out.format("response: %s\n", response); + System.out.format("\tname:%s\n", response.getName()); + } catch (ApiException ex) { + System.out.format("Exception: %s\n", ex.getLocalizedMessage()); + } + } + } +} + +// [END aiplatform_create_batch_prediction_job_text_entity_extraction_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextSentimentAnalysisSample.java b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextSentimentAnalysisSample.java new file mode 100644 index 00000000000..8191618c9fe --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobTextSentimentAnalysisSample.java @@ -0,0 +1,94 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_batch_prediction_job_text_sentiment_analysis_sample] +import com.google.api.gax.rpc.ApiException; +import com.google.cloud.aiplatform.v1.BatchPredictionJob; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.ModelName; +import java.io.IOException; + +public class CreateBatchPredictionJobTextSentimentAnalysisSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String location = "us-central1"; + String displayName = "DISPLAY_NAME"; + String modelId = "MODEL_ID"; + String gcsSourceUri = "GCS_SOURCE_URI"; + String gcsDestinationOutputUriPrefix = "GCS_DESTINATION_OUTPUT_URI_PREFIX"; + createBatchPredictionJobTextSentimentAnalysisSample( + project, location, displayName, modelId, gcsSourceUri, gcsDestinationOutputUriPrefix); + } + + static void createBatchPredictionJobTextSentimentAnalysisSample( + String project, + String location, + String displayName, + String modelId, + String gcsSourceUri, + String gcsDestinationOutputUriPrefix) + throws IOException { + // The AI Platform services require regional API endpoints. + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + try { + String modelName = ModelName.of(project, location, modelId).toString(); + GcsSource gcsSource = GcsSource.newBuilder().addUris(gcsSourceUri).build(); + BatchPredictionJob.InputConfig inputConfig = + BatchPredictionJob.InputConfig.newBuilder() + .setInstancesFormat("jsonl") + .setGcsSource(gcsSource) + .build(); + GcsDestination gcsDestination = + GcsDestination.newBuilder().setOutputUriPrefix(gcsDestinationOutputUriPrefix).build(); + BatchPredictionJob.OutputConfig outputConfig = + BatchPredictionJob.OutputConfig.newBuilder() + .setPredictionsFormat("jsonl") + .setGcsDestination(gcsDestination) + .build(); + BatchPredictionJob batchPredictionJob = + BatchPredictionJob.newBuilder() + .setDisplayName(displayName) + .setModel(modelName) + .setInputConfig(inputConfig) + .setOutputConfig(outputConfig) + .build(); + LocationName parent = LocationName.of(project, location); + BatchPredictionJob response = client.createBatchPredictionJob(parent, batchPredictionJob); + System.out.format("response: %s\n", response); + } catch (ApiException ex) { + System.out.format("Exception: %s\n", ex.getLocalizedMessage()); + } + } + } +} + +// [END aiplatform_create_batch_prediction_job_text_sentiment_analysis_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoActionRecognitionSample.java b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoActionRecognitionSample.java new file mode 100644 index 00000000000..0d0f68e5418 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoActionRecognitionSample.java @@ -0,0 +1,94 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_batch_prediction_job_video_action_recognition_sample] +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.BatchPredictionJob; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.protobuf.Value; +import java.io.IOException; + +public class CreateBatchPredictionJobVideoActionRecognitionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String displayName = "DISPLAY_NAME"; + String model = "MODEL"; + String gcsSourceUri = "GCS_SOURCE_URI"; + String gcsDestinationOutputUriPrefix = "GCS_DESTINATION_OUTPUT_URI_PREFIX"; + createBatchPredictionJobVideoActionRecognitionSample( + project, displayName, model, gcsSourceUri, gcsDestinationOutputUriPrefix); + } + + static void createBatchPredictionJobVideoActionRecognitionSample( + String project, + String displayName, + String model, + String gcsSourceUri, + String gcsDestinationOutputUriPrefix) + throws IOException { + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + Value modelParameters = ValueConverter.EMPTY_VALUE; + GcsSource gcsSource = GcsSource.newBuilder().addUris(gcsSourceUri).build(); + BatchPredictionJob.InputConfig inputConfig = + BatchPredictionJob.InputConfig.newBuilder() + .setInstancesFormat("jsonl") + .setGcsSource(gcsSource) + .build(); + GcsDestination gcsDestination = + GcsDestination.newBuilder().setOutputUriPrefix(gcsDestinationOutputUriPrefix).build(); + BatchPredictionJob.OutputConfig outputConfig = + BatchPredictionJob.OutputConfig.newBuilder() + .setPredictionsFormat("jsonl") + .setGcsDestination(gcsDestination) + .build(); + + String modelName = ModelName.of(project, location, model).toString(); + + BatchPredictionJob batchPredictionJob = + BatchPredictionJob.newBuilder() + .setDisplayName(displayName) + .setModel(modelName) + .setModelParameters(modelParameters) + .setInputConfig(inputConfig) + .setOutputConfig(outputConfig) + .build(); + LocationName parent = LocationName.of(project, location); + BatchPredictionJob response = client.createBatchPredictionJob(parent, batchPredictionJob); + System.out.format("response: %s\n", response); + System.out.format("\tName: %s\n", response.getName()); + } + } +} + +// [END aiplatform_create_batch_prediction_job_video_action_recognition_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoClassificationSample.java b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoClassificationSample.java new file mode 100644 index 00000000000..905ab46b7c5 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoClassificationSample.java @@ -0,0 +1,204 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_batch_prediction_job_video_classification_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.BatchDedicatedResources; +import com.google.cloud.aiplatform.v1.BatchPredictionJob; +import com.google.cloud.aiplatform.v1.BatchPredictionJob.InputConfig; +import com.google.cloud.aiplatform.v1.BatchPredictionJob.OutputConfig; +import com.google.cloud.aiplatform.v1.BatchPredictionJob.OutputInfo; +import com.google.cloud.aiplatform.v1.BigQueryDestination; +import com.google.cloud.aiplatform.v1.BigQuerySource; +import com.google.cloud.aiplatform.v1.CompletionStats; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.MachineSpec; +import com.google.cloud.aiplatform.v1.ManualBatchTuningParameters; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.cloud.aiplatform.v1.ResourcesConsumed; +import com.google.cloud.aiplatform.v1.schema.predict.params.VideoClassificationPredictionParams; +import com.google.protobuf.Any; +import com.google.protobuf.Value; +import com.google.rpc.Status; +import java.io.IOException; +import java.util.List; + +public class CreateBatchPredictionJobVideoClassificationSample { + + public static void main(String[] args) throws IOException { + String batchPredictionDisplayName = "YOUR_VIDEO_CLASSIFICATION_DISPLAY_NAME"; + String modelId = "YOUR_MODEL_ID"; + String gcsSourceUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_video_source/[file.csv/file.jsonl]"; + String gcsDestinationOutputUriPrefix = + "gs://YOUR_GCS_SOURCE_BUCKET/destination_output_uri_prefix/"; + String project = "YOUR_PROJECT_ID"; + createBatchPredictionJobVideoClassification( + batchPredictionDisplayName, modelId, gcsSourceUri, gcsDestinationOutputUriPrefix, project); + } + + static void createBatchPredictionJobVideoClassification( + String batchPredictionDisplayName, + String modelId, + String gcsSourceUri, + String gcsDestinationOutputUriPrefix, + String project) + throws IOException { + JobServiceSettings jobServiceSettings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient jobServiceClient = JobServiceClient.create(jobServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + + VideoClassificationPredictionParams modelParamsObj = + VideoClassificationPredictionParams.newBuilder() + .setConfidenceThreshold(((float) 0.5)) + .setMaxPredictions(10000) + .setSegmentClassification(true) + .setShotClassification(true) + .setOneSecIntervalClassification(true) + .build(); + + Value modelParameters = ValueConverter.toValue(modelParamsObj); + + ModelName modelName = ModelName.of(project, location, modelId); + GcsSource.Builder gcsSource = GcsSource.newBuilder(); + gcsSource.addUris(gcsSourceUri); + InputConfig inputConfig = + InputConfig.newBuilder().setInstancesFormat("jsonl").setGcsSource(gcsSource).build(); + + GcsDestination gcsDestination = + GcsDestination.newBuilder().setOutputUriPrefix(gcsDestinationOutputUriPrefix).build(); + OutputConfig outputConfig = + OutputConfig.newBuilder() + .setPredictionsFormat("jsonl") + .setGcsDestination(gcsDestination) + .build(); + + BatchPredictionJob batchPredictionJob = + BatchPredictionJob.newBuilder() + .setDisplayName(batchPredictionDisplayName) + .setModel(modelName.toString()) + .setModelParameters(modelParameters) + .setInputConfig(inputConfig) + .setOutputConfig(outputConfig) + .build(); + BatchPredictionJob batchPredictionJobResponse = + jobServiceClient.createBatchPredictionJob(locationName, batchPredictionJob); + + System.out.println("Create Batch Prediction Job Video Classification Response"); + System.out.format("\tName: %s\n", batchPredictionJobResponse.getName()); + System.out.format("\tDisplay Name: %s\n", batchPredictionJobResponse.getDisplayName()); + System.out.format("\tModel %s\n", batchPredictionJobResponse.getModel()); + System.out.format( + "\tModel Parameters: %s\n", batchPredictionJobResponse.getModelParameters()); + + System.out.format("\tState: %s\n", batchPredictionJobResponse.getState()); + System.out.format("\tCreate Time: %s\n", batchPredictionJobResponse.getCreateTime()); + System.out.format("\tStart Time: %s\n", batchPredictionJobResponse.getStartTime()); + System.out.format("\tEnd Time: %s\n", batchPredictionJobResponse.getEndTime()); + System.out.format("\tUpdate Time: %s\n", batchPredictionJobResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", batchPredictionJobResponse.getLabelsMap()); + + InputConfig inputConfigResponse = batchPredictionJobResponse.getInputConfig(); + System.out.println("\tInput Config"); + System.out.format("\t\tInstances Format: %s\n", inputConfigResponse.getInstancesFormat()); + + GcsSource gcsSourceResponse = inputConfigResponse.getGcsSource(); + System.out.println("\t\tGcs Source"); + System.out.format("\t\t\tUris %s\n", gcsSourceResponse.getUrisList()); + + BigQuerySource bigQuerySource = inputConfigResponse.getBigquerySource(); + System.out.println("\t\tBigquery Source"); + System.out.format("\t\t\tInput_uri: %s\n", bigQuerySource.getInputUri()); + + OutputConfig outputConfigResponse = batchPredictionJobResponse.getOutputConfig(); + System.out.println("\tOutput Config"); + System.out.format( + "\t\tPredictions Format: %s\n", outputConfigResponse.getPredictionsFormat()); + + GcsDestination gcsDestinationResponse = outputConfigResponse.getGcsDestination(); + System.out.println("\t\tGcs Destination"); + System.out.format( + "\t\t\tOutput Uri Prefix: %s\n", gcsDestinationResponse.getOutputUriPrefix()); + + BigQueryDestination bigQueryDestination = outputConfigResponse.getBigqueryDestination(); + System.out.println("\t\tBig Query Destination"); + System.out.format("\t\t\tOutput Uri: %s\n", bigQueryDestination.getOutputUri()); + + BatchDedicatedResources batchDedicatedResources = + batchPredictionJobResponse.getDedicatedResources(); + System.out.println("\tBatch Dedicated Resources"); + System.out.format( + "\t\tStarting Replica Count: %s\n", batchDedicatedResources.getStartingReplicaCount()); + System.out.format( + "\t\tMax Replica Count: %s\n", batchDedicatedResources.getMaxReplicaCount()); + + MachineSpec machineSpec = batchDedicatedResources.getMachineSpec(); + System.out.println("\t\tMachine Spec"); + System.out.format("\t\t\tMachine Type: %s\n", machineSpec.getMachineType()); + System.out.format("\t\t\tAccelerator Type: %s\n", machineSpec.getAcceleratorType()); + System.out.format("\t\t\tAccelerator Count: %s\n", machineSpec.getAcceleratorCount()); + + ManualBatchTuningParameters manualBatchTuningParameters = + batchPredictionJobResponse.getManualBatchTuningParameters(); + System.out.println("\tManual Batch Tuning Parameters"); + System.out.format("\t\tBatch Size: %s\n", manualBatchTuningParameters.getBatchSize()); + + OutputInfo outputInfo = batchPredictionJobResponse.getOutputInfo(); + System.out.println("\tOutput Info"); + System.out.format("\t\tGcs Output Directory: %s\n", outputInfo.getGcsOutputDirectory()); + System.out.format("\t\tBigquery Output Dataset: %s\n", outputInfo.getBigqueryOutputDataset()); + + Status status = batchPredictionJobResponse.getError(); + System.out.println("\tError"); + System.out.format("\t\tCode: %s\n", status.getCode()); + System.out.format("\t\tMessage: %s\n", status.getMessage()); + List details = status.getDetailsList(); + + for (Status partialFailure : batchPredictionJobResponse.getPartialFailuresList()) { + System.out.println("\tPartial Failure"); + System.out.format("\t\tCode: %s\n", partialFailure.getCode()); + System.out.format("\t\tMessage: %s\n", partialFailure.getMessage()); + List partialFailureDetailsList = partialFailure.getDetailsList(); + } + + ResourcesConsumed resourcesConsumed = batchPredictionJobResponse.getResourcesConsumed(); + System.out.println("\tResources Consumed"); + System.out.format("\t\tReplica Hours: %s\n", resourcesConsumed.getReplicaHours()); + + CompletionStats completionStats = batchPredictionJobResponse.getCompletionStats(); + System.out.println("\tCompletion Stats"); + System.out.format("\t\tSuccessful Count: %s\n", completionStats.getSuccessfulCount()); + System.out.format("\t\tFailed Count: %s\n", completionStats.getFailedCount()); + System.out.format("\t\tIncomplete Count: %s\n", completionStats.getIncompleteCount()); + } + } +} +// [END aiplatform_create_batch_prediction_job_video_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoObjectTrackingSample.java b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoObjectTrackingSample.java new file mode 100644 index 00000000000..860bc8da82a --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateBatchPredictionJobVideoObjectTrackingSample.java @@ -0,0 +1,201 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_batch_prediction_job_video_object_tracking_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.BatchDedicatedResources; +import com.google.cloud.aiplatform.v1.BatchPredictionJob; +import com.google.cloud.aiplatform.v1.BatchPredictionJob.InputConfig; +import com.google.cloud.aiplatform.v1.BatchPredictionJob.OutputConfig; +import com.google.cloud.aiplatform.v1.BatchPredictionJob.OutputInfo; +import com.google.cloud.aiplatform.v1.BigQueryDestination; +import com.google.cloud.aiplatform.v1.BigQuerySource; +import com.google.cloud.aiplatform.v1.CompletionStats; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.MachineSpec; +import com.google.cloud.aiplatform.v1.ManualBatchTuningParameters; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.cloud.aiplatform.v1.ResourcesConsumed; +import com.google.cloud.aiplatform.v1.schema.predict.params.VideoObjectTrackingPredictionParams; +import com.google.protobuf.Any; +import com.google.protobuf.Value; +import com.google.rpc.Status; +import java.io.IOException; +import java.util.List; + +public class CreateBatchPredictionJobVideoObjectTrackingSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String batchPredictionDisplayName = "YOUR_VIDEO_OBJECT_TRACKING_DISPLAY_NAME"; + String modelId = "YOUR_MODEL_ID"; + String gcsSourceUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_video_source/[file.csv/file.jsonl]"; + String gcsDestinationOutputUriPrefix = + "gs://YOUR_GCS_SOURCE_BUCKET/destination_output_uri_prefix/"; + String project = "YOUR_PROJECT_ID"; + batchPredictionJobVideoObjectTracking( + batchPredictionDisplayName, modelId, gcsSourceUri, gcsDestinationOutputUriPrefix, project); + } + + static void batchPredictionJobVideoObjectTracking( + String batchPredictionDisplayName, + String modelId, + String gcsSourceUri, + String gcsDestinationOutputUriPrefix, + String project) + throws IOException { + JobServiceSettings jobServiceSettings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient jobServiceClient = JobServiceClient.create(jobServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + ModelName modelName = ModelName.of(project, location, modelId); + + VideoObjectTrackingPredictionParams modelParamsObj = + VideoObjectTrackingPredictionParams.newBuilder() + .setConfidenceThreshold(((float) 0.5)) + .build(); + + Value modelParameters = ValueConverter.toValue(modelParamsObj); + + GcsSource.Builder gcsSource = GcsSource.newBuilder(); + gcsSource.addUris(gcsSourceUri); + InputConfig inputConfig = + InputConfig.newBuilder().setInstancesFormat("jsonl").setGcsSource(gcsSource).build(); + + GcsDestination gcsDestination = + GcsDestination.newBuilder().setOutputUriPrefix(gcsDestinationOutputUriPrefix).build(); + OutputConfig outputConfig = + OutputConfig.newBuilder() + .setPredictionsFormat("jsonl") + .setGcsDestination(gcsDestination) + .build(); + + BatchPredictionJob batchPredictionJob = + BatchPredictionJob.newBuilder() + .setDisplayName(batchPredictionDisplayName) + .setModel(modelName.toString()) + .setModelParameters(modelParameters) + .setInputConfig(inputConfig) + .setOutputConfig(outputConfig) + .build(); + BatchPredictionJob batchPredictionJobResponse = + jobServiceClient.createBatchPredictionJob(locationName, batchPredictionJob); + + System.out.println("Create Batch Prediction Job Video Object Tracking Response"); + System.out.format("\tName: %s\n", batchPredictionJobResponse.getName()); + System.out.format("\tDisplay Name: %s\n", batchPredictionJobResponse.getDisplayName()); + System.out.format("\tModel %s\n", batchPredictionJobResponse.getModel()); + System.out.format( + "\tModel Parameters: %s\n", batchPredictionJobResponse.getModelParameters()); + + System.out.format("\tState: %s\n", batchPredictionJobResponse.getState()); + System.out.format("\tCreate Time: %s\n", batchPredictionJobResponse.getCreateTime()); + System.out.format("\tStart Time: %s\n", batchPredictionJobResponse.getStartTime()); + System.out.format("\tEnd Time: %s\n", batchPredictionJobResponse.getEndTime()); + System.out.format("\tUpdate Time: %s\n", batchPredictionJobResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", batchPredictionJobResponse.getLabelsMap()); + + InputConfig inputConfigResponse = batchPredictionJobResponse.getInputConfig(); + System.out.println("\tInput Config"); + System.out.format("\t\tInstances Format: %s\n", inputConfigResponse.getInstancesFormat()); + + GcsSource gcsSourceResponse = inputConfigResponse.getGcsSource(); + System.out.println("\t\tGcs Source"); + System.out.format("\t\t\tUris %s\n", gcsSourceResponse.getUrisList()); + + BigQuerySource bigQuerySource = inputConfigResponse.getBigquerySource(); + System.out.println("\t\tBigquery Source"); + System.out.format("\t\t\tInput_uri: %s\n", bigQuerySource.getInputUri()); + + OutputConfig outputConfigResponse = batchPredictionJobResponse.getOutputConfig(); + System.out.println("\tOutput Config"); + System.out.format( + "\t\tPredictions Format: %s\n", outputConfigResponse.getPredictionsFormat()); + + GcsDestination gcsDestinationResponse = outputConfigResponse.getGcsDestination(); + System.out.println("\t\tGcs Destination"); + System.out.format( + "\t\t\tOutput Uri Prefix: %s\n", gcsDestinationResponse.getOutputUriPrefix()); + + BigQueryDestination bigQueryDestination = outputConfigResponse.getBigqueryDestination(); + System.out.println("\t\tBig Query Destination"); + System.out.format("\t\t\tOutput Uri: %s\n", bigQueryDestination.getOutputUri()); + + BatchDedicatedResources batchDedicatedResources = + batchPredictionJobResponse.getDedicatedResources(); + System.out.println("\tBatch Dedicated Resources"); + System.out.format( + "\t\tStarting Replica Count: %s\n", batchDedicatedResources.getStartingReplicaCount()); + System.out.format( + "\t\tMax Replica Count: %s\n", batchDedicatedResources.getMaxReplicaCount()); + + MachineSpec machineSpec = batchDedicatedResources.getMachineSpec(); + System.out.println("\t\tMachine Spec"); + System.out.format("\t\t\tMachine Type: %s\n", machineSpec.getMachineType()); + System.out.format("\t\t\tAccelerator Type: %s\n", machineSpec.getAcceleratorType()); + System.out.format("\t\t\tAccelerator Count: %s\n", machineSpec.getAcceleratorCount()); + + ManualBatchTuningParameters manualBatchTuningParameters = + batchPredictionJobResponse.getManualBatchTuningParameters(); + System.out.println("\tManual Batch Tuning Parameters"); + System.out.format("\t\tBatch Size: %s\n", manualBatchTuningParameters.getBatchSize()); + + OutputInfo outputInfo = batchPredictionJobResponse.getOutputInfo(); + System.out.println("\tOutput Info"); + System.out.format("\t\tGcs Output Directory: %s\n", outputInfo.getGcsOutputDirectory()); + System.out.format("\t\tBigquery Output Dataset: %s\n", outputInfo.getBigqueryOutputDataset()); + + Status status = batchPredictionJobResponse.getError(); + System.out.println("\tError"); + System.out.format("\t\tCode: %s\n", status.getCode()); + System.out.format("\t\tMessage: %s\n", status.getMessage()); + List details = status.getDetailsList(); + + for (Status partialFailure : batchPredictionJobResponse.getPartialFailuresList()) { + System.out.println("\tPartial Failure"); + System.out.format("\t\tCode: %s\n", partialFailure.getCode()); + System.out.format("\t\tMessage: %s\n", partialFailure.getMessage()); + List partialFailureDetailsList = partialFailure.getDetailsList(); + } + + ResourcesConsumed resourcesConsumed = batchPredictionJobResponse.getResourcesConsumed(); + System.out.println("\tResources Consumed"); + System.out.format("\t\tReplica Hours: %s\n", resourcesConsumed.getReplicaHours()); + + CompletionStats completionStats = batchPredictionJobResponse.getCompletionStats(); + System.out.println("\tCompletion Stats"); + System.out.format("\t\tSuccessful Count: %s\n", completionStats.getSuccessfulCount()); + System.out.format("\t\tFailed Count: %s\n", completionStats.getFailedCount()); + System.out.format("\t\tIncomplete Count: %s\n", completionStats.getIncompleteCount()); + } + } +} +// [END aiplatform_create_batch_prediction_job_video_object_tracking_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobActiveLearningSample.java b/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobActiveLearningSample.java new file mode 100644 index 00000000000..1a0076fbc4b --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobActiveLearningSample.java @@ -0,0 +1,97 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_data_labeling_job_active_learning_sample] +import com.google.cloud.aiplatform.v1.ActiveLearningConfig; +import com.google.cloud.aiplatform.v1.DataLabelingJob; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; + +public class CreateDataLabelingJobActiveLearningSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String displayName = "DISPLAY_NAME"; + String dataset = "DATASET"; + String instructionUri = "INSTRUCTION_URI"; + String inputsSchemaUri = "INPUTS_SCHEMA_URI"; + String annotationSpec = "ANNOTATION_SPEC"; + createDataLabelingJobActiveLearningSample( + project, displayName, dataset, instructionUri, inputsSchemaUri, annotationSpec); + } + + static void createDataLabelingJobActiveLearningSample( + String project, + String displayName, + String dataset, + String instructionUri, + String inputsSchemaUri, + String annotationSpec) + throws IOException { + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + JsonArray jsonAnnotationSpecs = new JsonArray(); + jsonAnnotationSpecs.add(annotationSpec); + JsonObject jsonInputs = new JsonObject(); + jsonInputs.add("annotation_specs", jsonAnnotationSpecs); + Value.Builder inputsBuilder = Value.newBuilder(); + JsonFormat.parser().merge(jsonInputs.toString(), inputsBuilder); + Value inputs = inputsBuilder.build(); + ActiveLearningConfig activeLearningConfig = + ActiveLearningConfig.newBuilder().setMaxDataItemCount(1).build(); + + String datasetName = DatasetName.of(project, location, dataset).toString(); + + DataLabelingJob dataLabelingJob = + DataLabelingJob.newBuilder() + .setDisplayName(displayName) + .addDatasets(datasetName) + .setLabelerCount(1) + .setInstructionUri(instructionUri) + .setInputsSchemaUri(inputsSchemaUri) + .setInputs(inputs) + .putAnnotationLabels( + "aiplatform.googleapis.com/annotation_set_name", + "data_labeling_job_active_learning") + .setActiveLearningConfig(activeLearningConfig) + .build(); + LocationName parent = LocationName.of(project, location); + DataLabelingJob response = client.createDataLabelingJob(parent, dataLabelingJob); + System.out.format("response: %s\n", response); + System.out.format("Name: %s\n", response.getName()); + } + } +} + +// [END aiplatform_create_data_labeling_job_active_learning_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobImageSample.java b/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobImageSample.java new file mode 100644 index 00000000000..8d9dced5ec7 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobImageSample.java @@ -0,0 +1,115 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_data_labeling_job_image_sample] + +import com.google.cloud.aiplatform.v1.DataLabelingJob; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import com.google.type.Money; +import java.io.IOException; +import java.util.Map; + +public class CreateDataLabelingJobImageSample { + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String displayName = "YOUR_DATA_LABELING_DISPLAY_NAME"; + String datasetId = "YOUR_DATASET_ID"; + String instructionUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_data_labeling_source/file.pdf"; + String annotationSpec = "YOUR_ANNOTATION_SPEC"; + createDataLabelingJobImage(project, displayName, datasetId, instructionUri, annotationSpec); + } + + static void createDataLabelingJobImage( + String project, + String displayName, + String datasetId, + String instructionUri, + String annotationSpec) + throws IOException { + JobServiceSettings jobServiceSettings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient jobServiceClient = JobServiceClient.create(jobServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + + String jsonString = "{\"annotation_specs\": [ " + annotationSpec + "]}"; + Value.Builder annotationSpecValue = Value.newBuilder(); + JsonFormat.parser().merge(jsonString, annotationSpecValue); + + DatasetName datasetName = DatasetName.of(project, location, datasetId); + DataLabelingJob dataLabelingJob = + DataLabelingJob.newBuilder() + .setDisplayName(displayName) + .setLabelerCount(1) + .setInstructionUri(instructionUri) + .setInputsSchemaUri( + "gs://google-cloud-aiplatform/schema/datalabelingjob/inputs/" + + "image_classification.yaml") + .addDatasets(datasetName.toString()) + .setInputs(annotationSpecValue) + .putAnnotationLabels( + "aiplatform.googleapis.com/annotation_set_name", "my_test_saved_query") + .build(); + + DataLabelingJob dataLabelingJobResponse = + jobServiceClient.createDataLabelingJob(locationName, dataLabelingJob); + + System.out.println("Create Data Labeling Job Image Response"); + System.out.format("\tName: %s\n", dataLabelingJobResponse.getName()); + System.out.format("\tDisplay Name: %s\n", dataLabelingJobResponse.getDisplayName()); + System.out.format("\tDatasets: %s\n", dataLabelingJobResponse.getDatasetsList()); + System.out.format("\tLabeler Count: %s\n", dataLabelingJobResponse.getLabelerCount()); + System.out.format("\tInstruction Uri: %s\n", dataLabelingJobResponse.getInstructionUri()); + System.out.format("\tInputs Schema Uri: %s\n", dataLabelingJobResponse.getInputsSchemaUri()); + System.out.format("\tInputs: %s\n", dataLabelingJobResponse.getInputs()); + System.out.format("\tState: %s\n", dataLabelingJobResponse.getState()); + System.out.format("\tLabeling Progress: %s\n", dataLabelingJobResponse.getLabelingProgress()); + System.out.format("\tCreate Time: %s\n", dataLabelingJobResponse.getCreateTime()); + System.out.format("\tUpdate Time: %s\n", dataLabelingJobResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", dataLabelingJobResponse.getLabelsMap()); + System.out.format( + "\tSpecialist Pools: %s\n", dataLabelingJobResponse.getSpecialistPoolsList()); + for (Map.Entry annotationLabelMap : + dataLabelingJobResponse.getAnnotationLabelsMap().entrySet()) { + System.out.println("\tAnnotation Level"); + System.out.format("\t\tkey: %s\n", annotationLabelMap.getKey()); + System.out.format("\t\tvalue: %s\n", annotationLabelMap.getValue()); + } + Money money = dataLabelingJobResponse.getCurrentSpend(); + + System.out.println("\tCurrent Spend"); + System.out.format("\t\tCurrency Code: %s\n", money.getCurrencyCode()); + System.out.format("\t\tUnits: %s\n", money.getUnits()); + System.out.format("\t\tNanos: %s\n", money.getNanos()); + } + } +} +// [END aiplatform_create_data_labeling_job_image_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobSample.java b/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobSample.java new file mode 100644 index 00000000000..a677169d7bc --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobSample.java @@ -0,0 +1,117 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_data_labeling_job_sample] + +import com.google.cloud.aiplatform.v1.DataLabelingJob; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import com.google.type.Money; +import java.io.IOException; +import java.util.Map; + +public class CreateDataLabelingJobSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String displayName = "YOUR_DATA_LABELING_DISPLAY_NAME"; + String datasetId = "YOUR_DATASET_ID"; + String instructionUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_data_labeling_source/file.pdf"; + String inputsSchemaUri = "YOUR_INPUT_SCHEMA_URI"; + String annotationSpec = "YOUR_ANNOTATION_SPEC"; + createDataLabelingJob( + project, displayName, datasetId, instructionUri, inputsSchemaUri, annotationSpec); + } + + static void createDataLabelingJob( + String project, + String displayName, + String datasetId, + String instructionUri, + String inputsSchemaUri, + String annotationSpec) + throws IOException { + JobServiceSettings jobServiceSettings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient jobServiceClient = JobServiceClient.create(jobServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + + String jsonString = "{\"annotation_specs\": [ " + annotationSpec + "]}"; + Value.Builder annotationSpecValue = Value.newBuilder(); + JsonFormat.parser().merge(jsonString, annotationSpecValue); + + DatasetName datasetName = DatasetName.of(project, location, datasetId); + DataLabelingJob dataLabelingJob = + DataLabelingJob.newBuilder() + .setDisplayName(displayName) + .setLabelerCount(1) + .setInstructionUri(instructionUri) + .setInputsSchemaUri(inputsSchemaUri) + .addDatasets(datasetName.toString()) + .setInputs(annotationSpecValue) + .putAnnotationLabels( + "aiplatform.googleapis.com/annotation_set_name", "my_test_saved_query") + .build(); + + DataLabelingJob dataLabelingJobResponse = + jobServiceClient.createDataLabelingJob(locationName, dataLabelingJob); + + System.out.println("Create Data Labeling Job Response"); + System.out.format("\tName: %s\n", dataLabelingJobResponse.getName()); + System.out.format("\tDisplay Name: %s\n", dataLabelingJobResponse.getDisplayName()); + System.out.format("\tDatasets: %s\n", dataLabelingJobResponse.getDatasetsList()); + System.out.format("\tLabeler Count: %s\n", dataLabelingJobResponse.getLabelerCount()); + System.out.format("\tInstruction Uri: %s\n", dataLabelingJobResponse.getInstructionUri()); + System.out.format("\tInputs Schema Uri: %s\n", dataLabelingJobResponse.getInputsSchemaUri()); + System.out.format("\tInputs: %s\n", dataLabelingJobResponse.getInputs()); + System.out.format("\tState: %s\n", dataLabelingJobResponse.getState()); + System.out.format("\tLabeling Progress: %s\n", dataLabelingJobResponse.getLabelingProgress()); + System.out.format("\tCreate Time: %s\n", dataLabelingJobResponse.getCreateTime()); + System.out.format("\tUpdate Time: %s\n", dataLabelingJobResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", dataLabelingJobResponse.getLabelsMap()); + System.out.format( + "\tSpecialist Pools: %s\n", dataLabelingJobResponse.getSpecialistPoolsList()); + for (Map.Entry annotationLabelMap : + dataLabelingJobResponse.getAnnotationLabelsMap().entrySet()) { + System.out.println("\tAnnotation Level"); + System.out.format("\t\tkey: %s\n", annotationLabelMap.getKey()); + System.out.format("\t\tvalue: %s\n", annotationLabelMap.getValue()); + } + Money money = dataLabelingJobResponse.getCurrentSpend(); + + System.out.println("\tCurrent Spend"); + System.out.format("\t\tCurrency Code: %s\n", money.getCurrencyCode()); + System.out.format("\t\tUnits: %s\n", money.getUnits()); + System.out.format("\t\tNanos: %s\n", money.getNanos()); + } + } +} +// [END aiplatform_create_data_labeling_job_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobSpecialistPoolSample.java b/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobSpecialistPoolSample.java new file mode 100644 index 00000000000..528e4b2d0f5 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobSpecialistPoolSample.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_data_labeling_job_specialist_pool_sample] +import com.google.cloud.aiplatform.v1.DataLabelingJob; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.SpecialistPoolName; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; + +public class CreateDataLabelingJobSpecialistPoolSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String displayName = "DISPLAY_NAME"; + String dataset = "DATASET"; + String specialistPool = "SPECIALIST_POOL"; + String instructionUri = "INSTRUCTION_URI"; + String inputsSchemaUri = "INPUTS_SCHEMA_URI"; + String annotationSpec = "ANNOTATION_SPEC"; + createDataLabelingJobSpecialistPoolSample( + project, + displayName, + dataset, + specialistPool, + instructionUri, + inputsSchemaUri, + annotationSpec); + } + + static void createDataLabelingJobSpecialistPoolSample( + String project, + String displayName, + String dataset, + String specialistPool, + String instructionUri, + String inputsSchemaUri, + String annotationSpec) + throws IOException { + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + JsonArray jsonAnnotationSpecs = new JsonArray(); + jsonAnnotationSpecs.add(annotationSpec); + JsonObject jsonInputs = new JsonObject(); + jsonInputs.add("annotation_specs", jsonAnnotationSpecs); + Value.Builder inputsBuilder = Value.newBuilder(); + JsonFormat.parser().merge(jsonInputs.toString(), inputsBuilder); + Value inputs = inputsBuilder.build(); + + String datasetName = DatasetName.of(project, location, dataset).toString(); + String specialistPoolName = + SpecialistPoolName.of(project, location, specialistPool).toString(); + + DataLabelingJob dataLabelingJob = + DataLabelingJob.newBuilder() + .setDisplayName(displayName) + .addDatasets(datasetName) + .setLabelerCount(1) + .setInstructionUri(instructionUri) + .setInputsSchemaUri(inputsSchemaUri) + .setInputs(inputs) + .putAnnotationLabels( + "aiplatform.googleapis.com/annotation_set_name", + "data_labeling_job_specialist_pool") + .addSpecialistPools(specialistPoolName) + .build(); + LocationName parent = LocationName.of(project, location); + DataLabelingJob response = client.createDataLabelingJob(parent, dataLabelingJob); + System.out.format("response: %s\n", response); + } + } +} + +// [END aiplatform_create_data_labeling_job_specialist_pool_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobVideoSample.java b/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobVideoSample.java new file mode 100644 index 00000000000..cabf2399735 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDataLabelingJobVideoSample.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_data_labeling_job_video_sample] + +import com.google.cloud.aiplatform.v1.DataLabelingJob; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import com.google.type.Money; +import java.io.IOException; +import java.util.Map; + +public class CreateDataLabelingJobVideoSample { + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String displayName = "YOUR_DATA_LABELING_DISPLAY_NAME"; + String datasetId = "YOUR_DATASET_ID"; + String instructionUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_data_labeling_source/file.pdf"; + String annotationSpec = "YOUR_ANNOTATION_SPEC"; + createDataLabelingJobVideo(project, displayName, datasetId, instructionUri, annotationSpec); + } + + static void createDataLabelingJobVideo( + String project, + String displayName, + String datasetId, + String instructionUri, + String annotationSpec) + throws IOException { + JobServiceSettings jobServiceSettings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient jobServiceClient = JobServiceClient.create(jobServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + + String jsonString = "{\"annotation_specs\": [ " + annotationSpec + "]}"; + Value.Builder annotationSpecValue = Value.newBuilder(); + JsonFormat.parser().merge(jsonString, annotationSpecValue); + + DatasetName datasetName = DatasetName.of(project, location, datasetId); + DataLabelingJob dataLabelingJob = + DataLabelingJob.newBuilder() + .setDisplayName(displayName) + .setLabelerCount(1) + .setInstructionUri(instructionUri) + .setInputsSchemaUri( + "gs://google-cloud-aiplatform/schema/datalabelingjob/inputs/" + + "video_classification.yaml") + .addDatasets(datasetName.toString()) + .setInputs(annotationSpecValue) + .putAnnotationLabels( + "aiplatform.googleapis.com/annotation_set_name", "my_test_saved_query") + .build(); + + DataLabelingJob dataLabelingJobResponse = + jobServiceClient.createDataLabelingJob(locationName, dataLabelingJob); + + System.out.println("Create Data Labeling Job Video Response"); + System.out.format("\tName: %s\n", dataLabelingJobResponse.getName()); + System.out.format("\tDisplay Name: %s\n", dataLabelingJobResponse.getDisplayName()); + System.out.format("\tDatasets: %s\n", dataLabelingJobResponse.getDatasetsList()); + System.out.format("\tLabeler Count: %s\n", dataLabelingJobResponse.getLabelerCount()); + System.out.format("\tInstruction Uri: %s\n", dataLabelingJobResponse.getInstructionUri()); + System.out.format("\tInputs Schema Uri: %s\n", dataLabelingJobResponse.getInputsSchemaUri()); + System.out.format("\tInputs: %s\n", dataLabelingJobResponse.getInputs()); + System.out.format("\tState: %s\n", dataLabelingJobResponse.getState()); + System.out.format("\tLabeling Progress: %s\n", dataLabelingJobResponse.getLabelingProgress()); + System.out.format("\tCreate Time: %s\n", dataLabelingJobResponse.getCreateTime()); + System.out.format("\tUpdate Time: %s\n", dataLabelingJobResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", dataLabelingJobResponse.getLabelsMap()); + System.out.format( + "\tSpecialist Pools: %s\n", dataLabelingJobResponse.getSpecialistPoolsList()); + for (Map.Entry annotationLabelMap : + dataLabelingJobResponse.getAnnotationLabelsMap().entrySet()) { + System.out.println("\tAnnotation Level"); + System.out.format("\t\tkey: %s\n", annotationLabelMap.getKey()); + System.out.format("\t\tvalue: %s\n", annotationLabelMap.getValue()); + } + + Money money = dataLabelingJobResponse.getCurrentSpend(); + System.out.println("\tCurrent Spend"); + System.out.format("\t\tCurrency Code: %s\n", money.getCurrencyCode()); + System.out.format("\t\tUnits: %s\n", money.getUnits()); + System.out.format("\t\tNanos: %s\n", money.getNanos()); + } + } +} +// [END aiplatform_create_data_labeling_job_video_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDatasetImageSample.java b/aiplatform/src/main/java/aiplatform/CreateDatasetImageSample.java new file mode 100644 index 00000000000..6fcb27157ef --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDatasetImageSample.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_dataset_image_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1.Dataset; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateDatasetImageSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetDisplayName = "YOUR_DATASET_DISPLAY_NAME"; + createDatasetImageSample(project, datasetDisplayName); + } + + static void createDatasetImageSample(String project, String datasetDisplayName) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"; + LocationName locationName = LocationName.of(project, location); + Dataset dataset = + Dataset.newBuilder() + .setDisplayName(datasetDisplayName) + .setMetadataSchemaUri(metadataSchemaUri) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + System.out.format("Operation name: %s\n", datasetFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Dataset datasetResponse = datasetFuture.get(120, TimeUnit.SECONDS); + + System.out.println("Create Image Dataset Response"); + System.out.format("Name: %s\n", datasetResponse.getName()); + System.out.format("Display Name: %s\n", datasetResponse.getDisplayName()); + System.out.format("Metadata Schema Uri: %s\n", datasetResponse.getMetadataSchemaUri()); + System.out.format("Metadata: %s\n", datasetResponse.getMetadata()); + System.out.format("Create Time: %s\n", datasetResponse.getCreateTime()); + System.out.format("Update Time: %s\n", datasetResponse.getUpdateTime()); + System.out.format("Labels: %s\n", datasetResponse.getLabelsMap()); + } + } +} +// [END aiplatform_create_dataset_image_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDatasetSample.java b/aiplatform/src/main/java/aiplatform/CreateDatasetSample.java new file mode 100644 index 00000000000..0b0817f6904 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDatasetSample.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_dataset_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1.Dataset; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateDatasetSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetDisplayName = "YOUR_DATASET_DISPLAY_NAME"; + String metadataSchemaUri = "YOUR_METADATA_SCHEMA_URI"; + createDatasetSample(project, datasetDisplayName, metadataSchemaUri); + } + + static void createDatasetSample( + String project, String datasetDisplayName, String metadataSchemaUri) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + Dataset dataset = + Dataset.newBuilder() + .setDisplayName(datasetDisplayName) + .setMetadataSchemaUri(metadataSchemaUri) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + System.out.format("Operation name: %s\n", datasetFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Dataset datasetResponse = datasetFuture.get(300, TimeUnit.SECONDS); + + System.out.println("Create Dataset Response"); + System.out.format("Name: %s\n", datasetResponse.getName()); + System.out.format("Display Name: %s\n", datasetResponse.getDisplayName()); + System.out.format("Metadata Schema Uri: %s\n", datasetResponse.getMetadataSchemaUri()); + System.out.format("Metadata: %s\n", datasetResponse.getMetadata()); + System.out.format("Create Time: %s\n", datasetResponse.getCreateTime()); + System.out.format("Update Time: %s\n", datasetResponse.getUpdateTime()); + System.out.format("Labels: %s\n", datasetResponse.getLabelsMap()); + } + } +} +// [END aiplatform_create_dataset_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDatasetTabularBigquerySample.java b/aiplatform/src/main/java/aiplatform/CreateDatasetTabularBigquerySample.java new file mode 100644 index 00000000000..fd7628be2fa --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDatasetTabularBigquerySample.java @@ -0,0 +1,89 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_dataset_tabular_bigquery_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1.Dataset; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateDatasetTabularBigquerySample { + + public static void main(String[] args) + throws InterruptedException, ExecutionException, TimeoutException, IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String bigqueryDisplayName = "YOUR_DATASET_DISPLAY_NAME"; + String bigqueryUri = + "bq://YOUR_GOOGLE_CLOUD_PROJECT_ID.BIGQUERY_DATASET_ID.BIGQUERY_TABLE_OR_VIEW_ID"; + createDatasetTableBigquery(project, bigqueryDisplayName, bigqueryUri); + } + + static void createDatasetTableBigquery( + String project, String bigqueryDisplayName, String bigqueryUri) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + DatasetServiceSettings settings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = DatasetServiceClient.create(settings)) { + String location = "us-central1"; + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/metadata/tables_1.0.0.yaml"; + LocationName locationName = LocationName.of(project, location); + + String jsonString = + "{\"input_config\": {\"bigquery_source\": {\"uri\": \"" + bigqueryUri + "\"}}}"; + Value.Builder metaData = Value.newBuilder(); + JsonFormat.parser().merge(jsonString, metaData); + + Dataset dataset = + Dataset.newBuilder() + .setDisplayName(bigqueryDisplayName) + .setMetadataSchemaUri(metadataSchemaUri) + .setMetadata(metaData) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + System.out.format("Operation name: %s\n", datasetFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Dataset datasetResponse = datasetFuture.get(300, TimeUnit.SECONDS); + + System.out.println("Create Dataset Table Bigquery sample"); + System.out.format("Name: %s\n", datasetResponse.getName()); + System.out.format("Display Name: %s\n", datasetResponse.getDisplayName()); + System.out.format("Metadata Schema Uri: %s\n", datasetResponse.getMetadataSchemaUri()); + System.out.format("Metadata: %s\n", datasetResponse.getMetadata()); + } + } +} +// [END aiplatform_create_dataset_tabular_bigquery_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDatasetTabularGcsSample.java b/aiplatform/src/main/java/aiplatform/CreateDatasetTabularGcsSample.java new file mode 100644 index 00000000000..87bb139c9e2 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDatasetTabularGcsSample.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_dataset_tabular_gcs_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1.Dataset; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateDatasetTabularGcsSample { + + public static void main(String[] args) + throws InterruptedException, ExecutionException, TimeoutException, IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetDisplayName = "YOUR_DATASET_DISPLAY_NAME"; + String gcsSourceUri = "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_gcs_table/file.csv"; + ; + createDatasetTableGcs(project, datasetDisplayName, gcsSourceUri); + } + + static void createDatasetTableGcs(String project, String datasetDisplayName, String gcsSourceUri) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + DatasetServiceSettings settings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = DatasetServiceClient.create(settings)) { + String location = "us-central1"; + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/metadata/tables_1.0.0.yaml"; + LocationName locationName = LocationName.of(project, location); + + String jsonString = + "{\"input_config\": {\"gcs_source\": {\"uri\": [\"" + gcsSourceUri + "\"]}}}"; + Value.Builder metaData = Value.newBuilder(); + JsonFormat.parser().merge(jsonString, metaData); + + Dataset dataset = + Dataset.newBuilder() + .setDisplayName(datasetDisplayName) + .setMetadataSchemaUri(metadataSchemaUri) + .setMetadata(metaData) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + System.out.format("Operation name: %s\n", datasetFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Dataset datasetResponse = datasetFuture.get(300, TimeUnit.SECONDS); + + System.out.println("Create Dataset Table GCS sample"); + System.out.format("Name: %s\n", datasetResponse.getName()); + System.out.format("Display Name: %s\n", datasetResponse.getDisplayName()); + System.out.format("Metadata Schema Uri: %s\n", datasetResponse.getMetadataSchemaUri()); + System.out.format("Metadata: %s\n", datasetResponse.getMetadata()); + } + } +} +// [END aiplatform_create_dataset_tabular_gcs_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDatasetTextSample.java b/aiplatform/src/main/java/aiplatform/CreateDatasetTextSample.java new file mode 100644 index 00000000000..f919467e930 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDatasetTextSample.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_dataset_text_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1.Dataset; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateDatasetTextSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetDisplayName = "YOUR_DATASET_DISPLAY_NAME"; + + createDatasetTextSample(project, datasetDisplayName); + } + + static void createDatasetTextSample(String project, String datasetDisplayName) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/metadata/text_1.0.0.yaml"; + + LocationName locationName = LocationName.of(project, location); + Dataset dataset = + Dataset.newBuilder() + .setDisplayName(datasetDisplayName) + .setMetadataSchemaUri(metadataSchemaUri) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + System.out.format("Operation name: %s\n", datasetFuture.getInitialFuture().get().getName()); + + System.out.println("Waiting for operation to finish..."); + Dataset datasetResponse = datasetFuture.get(180, TimeUnit.SECONDS); + + System.out.println("Create Text Dataset Response"); + System.out.format("\tName: %s\n", datasetResponse.getName()); + System.out.format("\tDisplay Name: %s\n", datasetResponse.getDisplayName()); + System.out.format("\tMetadata Schema Uri: %s\n", datasetResponse.getMetadataSchemaUri()); + System.out.format("\tMetadata: %s\n", datasetResponse.getMetadata()); + System.out.format("\tCreate Time: %s\n", datasetResponse.getCreateTime()); + System.out.format("\tUpdate Time: %s\n", datasetResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", datasetResponse.getLabelsMap()); + } + } +} +// [END aiplatform_create_dataset_text_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateDatasetVideoSample.java b/aiplatform/src/main/java/aiplatform/CreateDatasetVideoSample.java new file mode 100644 index 00000000000..65e96a7c8b7 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateDatasetVideoSample.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_dataset_video_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1.Dataset; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateDatasetVideoSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetVideoDisplayName = "YOUR_DATASET_VIDEO_DISPLAY_NAME"; + createDatasetSample(datasetVideoDisplayName, project); + } + + static void createDatasetSample(String datasetVideoDisplayName, String project) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/metadata/video_1.0.0.yaml"; + LocationName locationName = LocationName.of(project, location); + Dataset dataset = + Dataset.newBuilder() + .setDisplayName(datasetVideoDisplayName) + .setMetadataSchemaUri(metadataSchemaUri) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + System.out.format("Operation name: %s\n", datasetFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Dataset datasetResponse = datasetFuture.get(300, TimeUnit.SECONDS); + + System.out.println("Create Dataset Video Response"); + System.out.format("Name: %s\n", datasetResponse.getName()); + System.out.format("Display Name: %s\n", datasetResponse.getDisplayName()); + System.out.format("Metadata Schema Uri: %s\n", datasetResponse.getMetadataSchemaUri()); + System.out.format("Metadata: %s\n", datasetResponse.getMetadata()); + System.out.format("Create Time: %s\n", datasetResponse.getCreateTime()); + System.out.format("Update Time: %s\n", datasetResponse.getUpdateTime()); + System.out.format("Labels: %s\n", datasetResponse.getLabelsMap()); + } + } +} +// [END aiplatform_create_dataset_video_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateEndpointSample.java b/aiplatform/src/main/java/aiplatform/CreateEndpointSample.java new file mode 100644 index 00000000000..e0d9214342c --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateEndpointSample.java @@ -0,0 +1,74 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_endpoint_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.CreateEndpointOperationMetadata; +import com.google.cloud.aiplatform.v1.Endpoint; +import com.google.cloud.aiplatform.v1.EndpointServiceClient; +import com.google.cloud.aiplatform.v1.EndpointServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateEndpointSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String endpointDisplayName = "YOUR_ENDPOINT_DISPLAY_NAME"; + createEndpointSample(project, endpointDisplayName); + } + + static void createEndpointSample(String project, String endpointDisplayName) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + EndpointServiceSettings endpointServiceSettings = + EndpointServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (EndpointServiceClient endpointServiceClient = + EndpointServiceClient.create(endpointServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + Endpoint endpoint = Endpoint.newBuilder().setDisplayName(endpointDisplayName).build(); + + OperationFuture endpointFuture = + endpointServiceClient.createEndpointAsync(locationName, endpoint); + System.out.format("Operation name: %s\n", endpointFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Endpoint endpointResponse = endpointFuture.get(300, TimeUnit.SECONDS); + + System.out.println("Create Endpoint Response"); + System.out.format("Name: %s\n", endpointResponse.getName()); + System.out.format("Display Name: %s\n", endpointResponse.getDisplayName()); + System.out.format("Description: %s\n", endpointResponse.getDescription()); + System.out.format("Labels: %s\n", endpointResponse.getLabelsMap()); + System.out.format("Create Time: %s\n", endpointResponse.getCreateTime()); + System.out.format("Update Time: %s\n", endpointResponse.getUpdateTime()); + } + } +} +// [END aiplatform_create_endpoint_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateEntityTypeMonitoringSample.java b/aiplatform/src/main/java/aiplatform/CreateEntityTypeMonitoringSample.java new file mode 100644 index 00000000000..b234d032497 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateEntityTypeMonitoringSample.java @@ -0,0 +1,114 @@ +/* + * 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. + * + * + * Create an entity type so that you can create its related features. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_create_entity_type_monitoring_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.CreateEntityTypeOperationMetadata; +import com.google.cloud.aiplatform.v1.CreateEntityTypeRequest; +import com.google.cloud.aiplatform.v1.EntityType; +import com.google.cloud.aiplatform.v1.FeaturestoreMonitoringConfig; +import com.google.cloud.aiplatform.v1.FeaturestoreMonitoringConfig.SnapshotAnalysis; +import com.google.cloud.aiplatform.v1.FeaturestoreName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateEntityTypeMonitoringSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String description = "YOUR_ENTITY_TYPE_DESCRIPTION"; + int monitoringIntervalDays = 1; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 300; + createEntityTypeMonitoringSample( + project, + featurestoreId, + entityTypeId, + description, + monitoringIntervalDays, + location, + endpoint, + timeout); + } + + static void createEntityTypeMonitoringSample( + String project, + String featurestoreId, + String entityTypeId, + String description, + int monitoringIntervalDays, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + FeaturestoreMonitoringConfig featurestoreMonitoringConfig = + FeaturestoreMonitoringConfig.newBuilder() + .setSnapshotAnalysis( + SnapshotAnalysis.newBuilder().setMonitoringIntervalDays(monitoringIntervalDays)) + .build(); + + EntityType entityType = + EntityType.newBuilder() + .setDescription(description) + .setMonitoringConfig(featurestoreMonitoringConfig) + .build(); + + CreateEntityTypeRequest createEntityTypeRequest = + CreateEntityTypeRequest.newBuilder() + .setParent(FeaturestoreName.of(project, location, featurestoreId).toString()) + .setEntityType(entityType) + .setEntityTypeId(entityTypeId) + .build(); + + OperationFuture entityTypeFuture = + featurestoreServiceClient.createEntityTypeAsync(createEntityTypeRequest); + System.out.format( + "Operation name: %s%n", entityTypeFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + EntityType entityTypeResponse = entityTypeFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Create Entity Type Monitoring Response"); + System.out.format("Name: %s%n", entityTypeResponse.getName()); + } + } +} +// [END aiplatform_create_entity_type_monitoring_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateEntityTypeSample.java b/aiplatform/src/main/java/aiplatform/CreateEntityTypeSample.java new file mode 100644 index 00000000000..012ac19615e --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateEntityTypeSample.java @@ -0,0 +1,93 @@ +/* + * 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. + * + * + * Create an entity type so that you can create its related features. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_create_entity_type_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.CreateEntityTypeOperationMetadata; +import com.google.cloud.aiplatform.v1.CreateEntityTypeRequest; +import com.google.cloud.aiplatform.v1.EntityType; +import com.google.cloud.aiplatform.v1.FeaturestoreName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateEntityTypeSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String description = "YOUR_ENTITY_TYPE_DESCRIPTION"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 300; + createEntityTypeSample( + project, featurestoreId, entityTypeId, description, location, endpoint, timeout); + } + + static void createEntityTypeSample( + String project, + String featurestoreId, + String entityTypeId, + String description, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + EntityType entityType = EntityType.newBuilder().setDescription(description).build(); + + CreateEntityTypeRequest createEntityTypeRequest = + CreateEntityTypeRequest.newBuilder() + .setParent(FeaturestoreName.of(project, location, featurestoreId).toString()) + .setEntityType(entityType) + .setEntityTypeId(entityTypeId) + .build(); + + OperationFuture entityTypeFuture = + featurestoreServiceClient.createEntityTypeAsync(createEntityTypeRequest); + System.out.format( + "Operation name: %s%n", entityTypeFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + EntityType entityTypeResponse = entityTypeFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Create Entity Type Response"); + System.out.format("Name: %s%n", entityTypeResponse.getName()); + } + } +} +// [END aiplatform_create_entity_type_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateFeatureSample.java b/aiplatform/src/main/java/aiplatform/CreateFeatureSample.java new file mode 100644 index 00000000000..10c18736f20 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateFeatureSample.java @@ -0,0 +1,108 @@ +/* + * 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. + * + * + * Create a single feature for an existing entity type. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_create_feature_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.CreateFeatureOperationMetadata; +import com.google.cloud.aiplatform.v1.CreateFeatureRequest; +import com.google.cloud.aiplatform.v1.EntityTypeName; +import com.google.cloud.aiplatform.v1.Feature; +import com.google.cloud.aiplatform.v1.Feature.ValueType; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateFeatureSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String featureId = "YOUR_FEATURE_ID"; + String description = "YOUR_FEATURE_DESCRIPTION"; + ValueType valueType = ValueType.STRING; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 900; + createFeatureSample( + project, + featurestoreId, + entityTypeId, + featureId, + description, + valueType, + location, + endpoint, + timeout); + } + + static void createFeatureSample( + String project, + String featurestoreId, + String entityTypeId, + String featureId, + String description, + ValueType valueType, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + Feature feature = + Feature.newBuilder().setDescription(description).setValueType(valueType).build(); + + CreateFeatureRequest createFeatureRequest = + CreateFeatureRequest.newBuilder() + .setParent( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .setFeature(feature) + .setFeatureId(featureId) + .build(); + + OperationFuture featureFuture = + featurestoreServiceClient.createFeatureAsync(createFeatureRequest); + System.out.format("Operation name: %s%n", featureFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Feature featureResponse = featureFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Create Feature Response"); + System.out.format("Name: %s%n", featureResponse.getName()); + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_create_feature_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateFeaturestoreFixedNodesSample.java b/aiplatform/src/main/java/aiplatform/CreateFeaturestoreFixedNodesSample.java new file mode 100644 index 00000000000..69add3ff170 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateFeaturestoreFixedNodesSample.java @@ -0,0 +1,95 @@ +/* + * 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. + * + * + * Create a featurestore resource to contain entity types and features. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_create_featurestore_fixed_nodes_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1beta1.CreateFeaturestoreOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.CreateFeaturestoreRequest; +import com.google.cloud.aiplatform.v1beta1.Featurestore; +import com.google.cloud.aiplatform.v1beta1.Featurestore.OnlineServingConfig; +import com.google.cloud.aiplatform.v1beta1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1beta1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1beta1.LocationName; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateFeaturestoreFixedNodesSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + int fixedNodeCount = 1; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 900; + createFeaturestoreFixedNodesSample( + project, featurestoreId, fixedNodeCount, location, endpoint, timeout); + } + + static void createFeaturestoreFixedNodesSample( + String project, + String featurestoreId, + int fixedNodeCount, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + OnlineServingConfig.Builder builderValue = + OnlineServingConfig.newBuilder().setFixedNodeCount(fixedNodeCount); + Featurestore featurestore = + Featurestore.newBuilder().setOnlineServingConfig(builderValue).build(); + + CreateFeaturestoreRequest createFeaturestoreRequest = + CreateFeaturestoreRequest.newBuilder() + .setParent(LocationName.of(project, location).toString()) + .setFeaturestore(featurestore) + .setFeaturestoreId(featurestoreId) + .build(); + + OperationFuture featurestoreFuture = + featurestoreServiceClient.createFeaturestoreAsync(createFeaturestoreRequest); + System.out.format( + "Operation name: %s%n", featurestoreFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Featurestore featurestoreResponse = featurestoreFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Create Featurestore Response"); + System.out.format("Name: %s%n", featurestoreResponse.getName()); + } + } +} +// [END aiplatform_create_featurestore_fixed_nodes_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateFeaturestoreSample.java b/aiplatform/src/main/java/aiplatform/CreateFeaturestoreSample.java new file mode 100644 index 00000000000..50e558fbb14 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateFeaturestoreSample.java @@ -0,0 +1,101 @@ +/* + * 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. + * + * + * Create a featurestore resource to contain entity types and features. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_create_featurestore_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1beta1.CreateFeaturestoreOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.CreateFeaturestoreRequest; +import com.google.cloud.aiplatform.v1beta1.Featurestore; +import com.google.cloud.aiplatform.v1beta1.Featurestore.OnlineServingConfig; +import com.google.cloud.aiplatform.v1beta1.Featurestore.OnlineServingConfig.Scaling; +import com.google.cloud.aiplatform.v1beta1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1beta1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1beta1.LocationName; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class CreateFeaturestoreSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + int minNodeCount = 1; + int maxNodeCount = 5; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 900; + createFeaturestoreSample( + project, featurestoreId, minNodeCount, maxNodeCount, location, endpoint, timeout); + } + + static void createFeaturestoreSample( + String project, + String featurestoreId, + int minNodeCount, + int maxNodeCount, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + OnlineServingConfig.Builder builderValue = + OnlineServingConfig.newBuilder() + .setScaling( + Scaling.newBuilder().setMinNodeCount(minNodeCount).setMaxNodeCount(maxNodeCount)); + Featurestore featurestore = + Featurestore.newBuilder().setOnlineServingConfig(builderValue).build(); + String parent = LocationName.of(project, location).toString(); + + CreateFeaturestoreRequest createFeaturestoreRequest = + CreateFeaturestoreRequest.newBuilder() + .setParent(parent) + .setFeaturestore(featurestore) + .setFeaturestoreId(featurestoreId) + .build(); + + OperationFuture featurestoreFuture = + featurestoreServiceClient.createFeaturestoreAsync(createFeaturestoreRequest); + System.out.format( + "Operation name: %s%n", featurestoreFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Featurestore featurestoreResponse = featurestoreFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Create Featurestore Response"); + System.out.format("Name: %s%n", featurestoreResponse.getName()); + } + } +} +// [END aiplatform_create_featurestore_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateHyperparameterTuningJobPythonPackageSample.java b/aiplatform/src/main/java/aiplatform/CreateHyperparameterTuningJobPythonPackageSample.java new file mode 100644 index 00000000000..0d86232e283 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateHyperparameterTuningJobPythonPackageSample.java @@ -0,0 +1,174 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_hyperparameter_tuning_job_python_package_sample] +import com.google.cloud.aiplatform.v1.AcceleratorType; +import com.google.cloud.aiplatform.v1.CustomJobSpec; +import com.google.cloud.aiplatform.v1.HyperparameterTuningJob; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.MachineSpec; +import com.google.cloud.aiplatform.v1.PythonPackageSpec; +import com.google.cloud.aiplatform.v1.StudySpec; +import com.google.cloud.aiplatform.v1.StudySpec.MetricSpec; +import com.google.cloud.aiplatform.v1.StudySpec.MetricSpec.GoalType; +import com.google.cloud.aiplatform.v1.StudySpec.ParameterSpec; +import com.google.cloud.aiplatform.v1.StudySpec.ParameterSpec.ConditionalParameterSpec; +import com.google.cloud.aiplatform.v1.StudySpec.ParameterSpec.ConditionalParameterSpec.DiscreteValueCondition; +import com.google.cloud.aiplatform.v1.StudySpec.ParameterSpec.DiscreteValueSpec; +import com.google.cloud.aiplatform.v1.StudySpec.ParameterSpec.DoubleValueSpec; +import com.google.cloud.aiplatform.v1.StudySpec.ParameterSpec.ScaleType; +import com.google.cloud.aiplatform.v1.WorkerPoolSpec; +import java.io.IOException; +import java.util.Arrays; + +public class CreateHyperparameterTuningJobPythonPackageSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String displayName = "DISPLAY_NAME"; + String executorImageUri = "EXECUTOR_IMAGE_URI"; + String packageUri = "PACKAGE_URI"; + String pythonModule = "PYTHON_MODULE"; + createHyperparameterTuningJobPythonPackageSample( + project, displayName, executorImageUri, packageUri, pythonModule); + } + + static void createHyperparameterTuningJobPythonPackageSample( + String project, + String displayName, + String executorImageUri, + String packageUri, + String pythonModule) + throws IOException { + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + // study spec + MetricSpec metric = + MetricSpec.newBuilder().setMetricId("val_rmse").setGoal(GoalType.MINIMIZE).build(); + + // decay + DoubleValueSpec doubleValueSpec = + DoubleValueSpec.newBuilder().setMinValue(1e-07).setMaxValue(1).build(); + ParameterSpec parameterDecaySpec = + ParameterSpec.newBuilder() + .setParameterId("decay") + .setDoubleValueSpec(doubleValueSpec) + .setScaleType(ScaleType.UNIT_LINEAR_SCALE) + .build(); + Double[] decayValues = {32.0, 64.0}; + DiscreteValueCondition discreteValueDecay = + DiscreteValueCondition.newBuilder().addAllValues(Arrays.asList(decayValues)).build(); + ConditionalParameterSpec conditionalParameterDecay = + ConditionalParameterSpec.newBuilder() + .setParameterSpec(parameterDecaySpec) + .setParentDiscreteValues(discreteValueDecay) + .build(); + + // learning rate + ParameterSpec parameterLearningSpec = + ParameterSpec.newBuilder() + .setParameterId("learning_rate") + .setDoubleValueSpec(doubleValueSpec) // Use the same min/max as for decay + .setScaleType(ScaleType.UNIT_LINEAR_SCALE) + .build(); + + Double[] learningRateValues = {4.0, 8.0, 16.0}; + DiscreteValueCondition discreteValueLearning = + DiscreteValueCondition.newBuilder() + .addAllValues(Arrays.asList(learningRateValues)) + .build(); + ConditionalParameterSpec conditionalParameterLearning = + ConditionalParameterSpec.newBuilder() + .setParameterSpec(parameterLearningSpec) + .setParentDiscreteValues(discreteValueLearning) + .build(); + + // batch size + Double[] batchSizeValues = {4.0, 8.0, 16.0, 32.0, 64.0, 128.0}; + + DiscreteValueSpec discreteValueSpec = + DiscreteValueSpec.newBuilder().addAllValues(Arrays.asList(batchSizeValues)).build(); + ParameterSpec parameter = + ParameterSpec.newBuilder() + .setParameterId("batch_size") + .setDiscreteValueSpec(discreteValueSpec) + .setScaleType(ScaleType.UNIT_LINEAR_SCALE) + .addConditionalParameterSpecs(conditionalParameterDecay) + .addConditionalParameterSpecs(conditionalParameterLearning) + .build(); + + // trial_job_spec + MachineSpec machineSpec = + MachineSpec.newBuilder() + .setMachineType("n1-standard-4") + .setAcceleratorType(AcceleratorType.NVIDIA_TESLA_K80) + .setAcceleratorCount(1) + .build(); + + PythonPackageSpec pythonPackageSpec = + PythonPackageSpec.newBuilder() + .setExecutorImageUri(executorImageUri) + .addPackageUris(packageUri) + .setPythonModule(pythonModule) + .build(); + + WorkerPoolSpec workerPoolSpec = + WorkerPoolSpec.newBuilder() + .setMachineSpec(machineSpec) + .setReplicaCount(1) + .setPythonPackageSpec(pythonPackageSpec) + .build(); + + StudySpec studySpec = + StudySpec.newBuilder() + .addMetrics(metric) + .addParameters(parameter) + .setAlgorithm(StudySpec.Algorithm.RANDOM_SEARCH) + .build(); + CustomJobSpec trialJobSpec = + CustomJobSpec.newBuilder().addWorkerPoolSpecs(workerPoolSpec).build(); + // hyperparameter_tuning_job + HyperparameterTuningJob hyperparameterTuningJob = + HyperparameterTuningJob.newBuilder() + .setDisplayName(displayName) + .setMaxTrialCount(4) + .setParallelTrialCount(2) + .setStudySpec(studySpec) + .setTrialJobSpec(trialJobSpec) + .build(); + LocationName parent = LocationName.of(project, location); + HyperparameterTuningJob response = + client.createHyperparameterTuningJob(parent, hyperparameterTuningJob); + System.out.format("response: %s\n", response); + System.out.format("Name: %s\n", response.getName()); + } + } +} + +// [END aiplatform_create_hyperparameter_tuning_job_python_package_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateHyperparameterTuningJobSample.java b/aiplatform/src/main/java/aiplatform/CreateHyperparameterTuningJobSample.java new file mode 100644 index 00000000000..b2295270a46 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateHyperparameterTuningJobSample.java @@ -0,0 +1,106 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_hyperparameter_tuning_job_sample] +import com.google.cloud.aiplatform.v1.AcceleratorType; +import com.google.cloud.aiplatform.v1.ContainerSpec; +import com.google.cloud.aiplatform.v1.CustomJobSpec; +import com.google.cloud.aiplatform.v1.HyperparameterTuningJob; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.MachineSpec; +import com.google.cloud.aiplatform.v1.StudySpec; +import com.google.cloud.aiplatform.v1.WorkerPoolSpec; +import java.io.IOException; + +public class CreateHyperparameterTuningJobSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String displayName = "DISPLAY_NAME"; + String containerImageUri = "CONTAINER_IMAGE_URI"; + createHyperparameterTuningJobSample(project, displayName, containerImageUri); + } + + static void createHyperparameterTuningJobSample( + String project, String displayName, String containerImageUri) throws IOException { + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + StudySpec.MetricSpec metric0 = + StudySpec.MetricSpec.newBuilder() + .setMetricId("accuracy") + .setGoal(StudySpec.MetricSpec.GoalType.MAXIMIZE) + .build(); + StudySpec.ParameterSpec.DoubleValueSpec doubleValueSpec = + StudySpec.ParameterSpec.DoubleValueSpec.newBuilder() + .setMinValue(0.001) + .setMaxValue(0.1) + .build(); + StudySpec.ParameterSpec parameter0 = + StudySpec.ParameterSpec.newBuilder() + // Learning rate. + .setParameterId("lr") + .setDoubleValueSpec(doubleValueSpec) + .build(); + StudySpec studySpec = + StudySpec.newBuilder().addMetrics(metric0).addParameters(parameter0).build(); + MachineSpec machineSpec = + MachineSpec.newBuilder() + .setMachineType("n1-standard-4") + .setAcceleratorType(AcceleratorType.NVIDIA_TESLA_K80) + .setAcceleratorCount(1) + .build(); + ContainerSpec containerSpec = + ContainerSpec.newBuilder().setImageUri(containerImageUri).build(); + WorkerPoolSpec workerPoolSpec0 = + WorkerPoolSpec.newBuilder() + .setMachineSpec(machineSpec) + .setReplicaCount(1) + .setContainerSpec(containerSpec) + .build(); + CustomJobSpec trialJobSpec = + CustomJobSpec.newBuilder().addWorkerPoolSpecs(workerPoolSpec0).build(); + HyperparameterTuningJob hyperparameterTuningJob = + HyperparameterTuningJob.newBuilder() + .setDisplayName(displayName) + .setMaxTrialCount(2) + .setParallelTrialCount(1) + .setMaxFailedTrialCount(1) + .setStudySpec(studySpec) + .setTrialJobSpec(trialJobSpec) + .build(); + LocationName parent = LocationName.of(project, location); + HyperparameterTuningJob response = + client.createHyperparameterTuningJob(parent, hyperparameterTuningJob); + System.out.format("response: %s\n", response); + System.out.format("Name: %s\n", response.getName()); + } + } +} + +// [END aiplatform_create_hyperparameter_tuning_job_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineCustomJobSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineCustomJobSample.java new file mode 100644 index 00000000000..53e9867a6ff --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineCustomJobSample.java @@ -0,0 +1,119 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_custom_job_sample] +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; + +public class CreateTrainingPipelineCustomJobSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String displayName = "DISPLAY_NAME"; + String modelDisplayName = "MODEL_DISPLAY_NAME"; + String containerImageUri = "CONTAINER_IMAGE_URI"; + String baseOutputDirectoryPrefix = "BASE_OUTPUT_DIRECTORY_PREFIX"; + createTrainingPipelineCustomJobSample( + project, displayName, modelDisplayName, containerImageUri, baseOutputDirectoryPrefix); + } + + static void createTrainingPipelineCustomJobSample( + String project, + String displayName, + String modelDisplayName, + String containerImageUri, + String baseOutputDirectoryPrefix) + throws IOException { + PipelineServiceSettings settings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient client = PipelineServiceClient.create(settings)) { + JsonObject jsonMachineSpec = new JsonObject(); + jsonMachineSpec.addProperty("machineType", "n1-standard-4"); + + JsonArray jsonArgs = new JsonArray(); + jsonArgs.add("--model_dir=$(AIP_MODEL_DIR)"); + + // A working docker image can be found at + // gs://cloud-samples-data/ai-platform/mnist_tfrecord/custom_job + JsonObject jsonContainerSpec = new JsonObject(); + jsonContainerSpec.addProperty("imageUri", containerImageUri); + jsonContainerSpec.add("args", jsonArgs); + + JsonObject jsonJsonWorkerPoolSpec0 = new JsonObject(); + jsonJsonWorkerPoolSpec0.addProperty("replicaCount", 1); + jsonJsonWorkerPoolSpec0.add("machineSpec", jsonMachineSpec); + jsonJsonWorkerPoolSpec0.add("containerSpec", jsonContainerSpec); + + JsonArray jsonWorkerPoolSpecs = new JsonArray(); + jsonWorkerPoolSpecs.add(jsonJsonWorkerPoolSpec0); + + JsonObject jsonBaseOutputDirectory = new JsonObject(); + // The GCS location for outputs must be accessible by the project's AI Platform + // service account. + jsonBaseOutputDirectory.addProperty("output_uri_prefix", baseOutputDirectoryPrefix); + + JsonObject jsonTrainingTaskInputs = new JsonObject(); + jsonTrainingTaskInputs.add("workerPoolSpecs", jsonWorkerPoolSpecs); + jsonTrainingTaskInputs.add("baseOutputDirectory", jsonBaseOutputDirectory); + + Value.Builder trainingTaskInputsBuilder = Value.newBuilder(); + JsonFormat.parser().merge(jsonTrainingTaskInputs.toString(), trainingTaskInputsBuilder); + Value trainingTaskInputs = trainingTaskInputsBuilder.build(); + String trainingTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/custom_task_1.0.0.yaml"; + String imageUri = "gcr.io/cloud-aiplatform/prediction/tf-cpu.1-15:latest"; + ModelContainerSpec containerSpec = + ModelContainerSpec.newBuilder().setImageUri(imageUri).build(); + Model modelToUpload = + Model.newBuilder() + .setDisplayName(modelDisplayName) + .setContainerSpec(containerSpec) + .build(); + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(displayName) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(trainingTaskInputs) + .setModelToUpload(modelToUpload) + .build(); + LocationName parent = LocationName.of(project, location); + TrainingPipeline response = client.createTrainingPipeline(parent, trainingPipeline); + System.out.format("response: %s\n", response); + System.out.format("Name: %s\n", response.getName()); + } + } +} + +// [END aiplatform_create_training_pipeline_custom_job_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineCustomTrainingManagedDatasetSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineCustomTrainingManagedDatasetSample.java new file mode 100644 index 00000000000..8fad236877c --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineCustomTrainingManagedDatasetSample.java @@ -0,0 +1,145 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_custom_training_managed_dataset_sample] +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; + +public class CreateTrainingPipelineCustomTrainingManagedDatasetSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String displayName = "DISPLAY_NAME"; + String modelDisplayName = "MODEL_DISPLAY_NAME"; + String datasetId = "DATASET_ID"; + String annotationSchemaUri = "ANNOTATION_SCHEMA_URI"; + String trainingContainerSpecImageUri = "TRAINING_CONTAINER_SPEC_IMAGE_URI"; + String modelContainerSpecImageUri = "MODEL_CONTAINER_SPEC_IMAGE_URI"; + String baseOutputUriPrefix = "BASE_OUTPUT_URI_PREFIX"; + createTrainingPipelineCustomTrainingManagedDatasetSample( + project, + displayName, + modelDisplayName, + datasetId, + annotationSchemaUri, + trainingContainerSpecImageUri, + modelContainerSpecImageUri, + baseOutputUriPrefix); + } + + static void createTrainingPipelineCustomTrainingManagedDatasetSample( + String project, + String displayName, + String modelDisplayName, + String datasetId, + String annotationSchemaUri, + String trainingContainerSpecImageUri, + String modelContainerSpecImageUri, + String baseOutputUriPrefix) + throws IOException { + PipelineServiceSettings settings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient client = PipelineServiceClient.create(settings)) { + JsonArray jsonArgs = new JsonArray(); + jsonArgs.add("--model-dir=$(AIP_MODEL_DIR)"); + // training_task_inputs + JsonObject jsonTrainingContainerSpec = new JsonObject(); + jsonTrainingContainerSpec.addProperty("imageUri", trainingContainerSpecImageUri); + // AIP_MODEL_DIR is set by the service according to baseOutputDirectory. + jsonTrainingContainerSpec.add("args", jsonArgs); + + JsonObject jsonMachineSpec = new JsonObject(); + jsonMachineSpec.addProperty("machineType", "n1-standard-8"); + + JsonObject jsonTrainingWorkerPoolSpec = new JsonObject(); + jsonTrainingWorkerPoolSpec.addProperty("replicaCount", 1); + jsonTrainingWorkerPoolSpec.add("machineSpec", jsonMachineSpec); + jsonTrainingWorkerPoolSpec.add("containerSpec", jsonTrainingContainerSpec); + + JsonArray jsonWorkerPoolSpecs = new JsonArray(); + jsonWorkerPoolSpecs.add(jsonTrainingWorkerPoolSpec); + + JsonObject jsonBaseOutputDirectory = new JsonObject(); + jsonBaseOutputDirectory.addProperty("outputUriPrefix", baseOutputUriPrefix); + + JsonObject jsonTrainingTaskInputs = new JsonObject(); + jsonTrainingTaskInputs.add("workerPoolSpecs", jsonWorkerPoolSpecs); + jsonTrainingTaskInputs.add("baseOutputDirectory", jsonBaseOutputDirectory); + + Value.Builder trainingTaskInputsBuilder = Value.newBuilder(); + JsonFormat.parser().merge(jsonTrainingTaskInputs.toString(), trainingTaskInputsBuilder); + Value trainingTaskInputs = trainingTaskInputsBuilder.build(); + // model_to_upload + ModelContainerSpec modelContainerSpec = + ModelContainerSpec.newBuilder().setImageUri(modelContainerSpecImageUri).build(); + Model model = + Model.newBuilder() + .setDisplayName(modelDisplayName) + .setContainerSpec(modelContainerSpec) + .build(); + GcsDestination gcsDestination = + GcsDestination.newBuilder().setOutputUriPrefix(baseOutputUriPrefix).build(); + + // input_data_config + InputDataConfig inputDataConfig = + InputDataConfig.newBuilder() + .setDatasetId(datasetId) + .setAnnotationSchemaUri(annotationSchemaUri) + .setGcsDestination(gcsDestination) + .build(); + + // training_task_definition + String customTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/custom_task_1.0.0.yaml"; + + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(displayName) + .setInputDataConfig(inputDataConfig) + .setTrainingTaskDefinition(customTaskDefinition) + .setTrainingTaskInputs(trainingTaskInputs) + .setModelToUpload(model) + .build(); + LocationName parent = LocationName.of(project, location); + TrainingPipeline response = client.createTrainingPipeline(parent, trainingPipeline); + System.out.format("response: %s\n", response); + System.out.format("Name: %s\n", response.getName()); + } + } +} + +// [END aiplatform_create_training_pipeline_custom_training_managed_dataset_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineImageClassificationSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineImageClassificationSample.java new file mode 100644 index 00000000000..4f9c1e2c57a --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineImageClassificationSample.java @@ -0,0 +1,210 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_image_classification_sample] +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.DeployedModelRef; +import com.google.cloud.aiplatform.v1.EnvVar; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.Model.ExportFormat; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.Port; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.PredictSchemata; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.cloud.aiplatform.v1.schema.trainingjob.definition.AutoMlImageClassificationInputs; +import com.google.cloud.aiplatform.v1.schema.trainingjob.definition.AutoMlImageClassificationInputs.ModelType; +import com.google.rpc.Status; +import java.io.IOException; + +public class CreateTrainingPipelineImageClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String trainingPipelineDisplayName = "YOUR_TRAINING_PIPELINE_DISPLAY_NAME"; + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String modelDisplayName = "YOUR_MODEL_DISPLAY_NAME"; + createTrainingPipelineImageClassificationSample( + project, trainingPipelineDisplayName, datasetId, modelDisplayName); + } + + static void createTrainingPipelineImageClassificationSample( + String project, String trainingPipelineDisplayName, String datasetId, String modelDisplayName) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + String trainingTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/" + + "automl_image_classification_1.0.0.yaml"; + LocationName locationName = LocationName.of(project, location); + + AutoMlImageClassificationInputs autoMlImageClassificationInputs = + AutoMlImageClassificationInputs.newBuilder() + .setModelType(ModelType.CLOUD) + .setMultiLabel(false) + .setBudgetMilliNodeHours(8000) + .setDisableEarlyStopping(false) + .build(); + + InputDataConfig trainingInputDataConfig = + InputDataConfig.newBuilder().setDatasetId(datasetId).build(); + Model model = Model.newBuilder().setDisplayName(modelDisplayName).build(); + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(trainingPipelineDisplayName) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(ValueConverter.toValue(autoMlImageClassificationInputs)) + .setInputDataConfig(trainingInputDataConfig) + .setModelToUpload(model) + .build(); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.createTrainingPipeline(locationName, trainingPipeline); + + System.out.println("Create Training Pipeline Image Classification Response"); + System.out.format("Name: %s\n", trainingPipelineResponse.getName()); + System.out.format("Display Name: %s\n", trainingPipelineResponse.getDisplayName()); + + System.out.format( + "Training Task Definition %s\n", trainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "Training Task Inputs: %s\n", trainingPipelineResponse.getTrainingTaskInputs()); + System.out.format( + "Training Task Metadata: %s\n", trainingPipelineResponse.getTrainingTaskMetadata()); + System.out.format("State: %s\n", trainingPipelineResponse.getState()); + + System.out.format("Create Time: %s\n", trainingPipelineResponse.getCreateTime()); + System.out.format("StartTime %s\n", trainingPipelineResponse.getStartTime()); + System.out.format("End Time: %s\n", trainingPipelineResponse.getEndTime()); + System.out.format("Update Time: %s\n", trainingPipelineResponse.getUpdateTime()); + System.out.format("Labels: %s\n", trainingPipelineResponse.getLabelsMap()); + + InputDataConfig inputDataConfig = trainingPipelineResponse.getInputDataConfig(); + System.out.println("Input Data Config"); + System.out.format("Dataset Id: %s", inputDataConfig.getDatasetId()); + System.out.format("Annotations Filter: %s\n", inputDataConfig.getAnnotationsFilter()); + + FractionSplit fractionSplit = inputDataConfig.getFractionSplit(); + System.out.println("Fraction Split"); + System.out.format("Training Fraction: %s\n", fractionSplit.getTrainingFraction()); + System.out.format("Validation Fraction: %s\n", fractionSplit.getValidationFraction()); + System.out.format("Test Fraction: %s\n", fractionSplit.getTestFraction()); + + FilterSplit filterSplit = inputDataConfig.getFilterSplit(); + System.out.println("Filter Split"); + System.out.format("Training Filter: %s\n", filterSplit.getTrainingFilter()); + System.out.format("Validation Filter: %s\n", filterSplit.getValidationFilter()); + System.out.format("Test Filter: %s\n", filterSplit.getTestFilter()); + + PredefinedSplit predefinedSplit = inputDataConfig.getPredefinedSplit(); + System.out.println("Predefined Split"); + System.out.format("Key: %s\n", predefinedSplit.getKey()); + + TimestampSplit timestampSplit = inputDataConfig.getTimestampSplit(); + System.out.println("Timestamp Split"); + System.out.format("Training Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("Validation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("Test Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("Key: %s\n", timestampSplit.getKey()); + + Model modelResponse = trainingPipelineResponse.getModelToUpload(); + System.out.println("Model To Upload"); + System.out.format("Name: %s\n", modelResponse.getName()); + System.out.format("Display Name: %s\n", modelResponse.getDisplayName()); + System.out.format("Description: %s\n", modelResponse.getDescription()); + + System.out.format("Metadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("Metadata: %s\n", modelResponse.getMetadata()); + System.out.format("Training Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("Artifact Uri: %s\n", modelResponse.getArtifactUri()); + + System.out.format( + "Supported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList()); + System.out.format( + "Supported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList()); + System.out.format( + "Supported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList()); + + System.out.format("Create Time: %s\n", modelResponse.getCreateTime()); + System.out.format("Update Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("Labels: %sn\n", modelResponse.getLabelsMap()); + + PredictSchemata predictSchemata = modelResponse.getPredictSchemata(); + System.out.println("Predict Schemata"); + System.out.format("Instance Schema Uri: %s\n", predictSchemata.getInstanceSchemaUri()); + System.out.format("Parameters Schema Uri: %s\n", predictSchemata.getParametersSchemaUri()); + System.out.format("Prediction Schema Uri: %s\n", predictSchemata.getPredictionSchemaUri()); + + for (ExportFormat exportFormat : modelResponse.getSupportedExportFormatsList()) { + System.out.println("Supported Export Format"); + System.out.format("Id: %s\n", exportFormat.getId()); + } + + ModelContainerSpec modelContainerSpec = modelResponse.getContainerSpec(); + System.out.println("Container Spec"); + System.out.format("Image Uri: %s\n", modelContainerSpec.getImageUri()); + System.out.format("Command: %s\n", modelContainerSpec.getCommandList()); + System.out.format("Args: %s\n", modelContainerSpec.getArgsList()); + System.out.format("Predict Route: %s\n", modelContainerSpec.getPredictRoute()); + System.out.format("Health Route: %s\n", modelContainerSpec.getHealthRoute()); + + for (EnvVar envVar : modelContainerSpec.getEnvList()) { + System.out.println("Env"); + System.out.format("Name: %s\n", envVar.getName()); + System.out.format("Value: %s\n", envVar.getValue()); + } + + for (Port port : modelContainerSpec.getPortsList()) { + System.out.println("Port"); + System.out.format("Container Port: %s\n", port.getContainerPort()); + } + + for (DeployedModelRef deployedModelRef : modelResponse.getDeployedModelsList()) { + System.out.println("Deployed Model"); + System.out.format("Endpoint: %s\n", deployedModelRef.getEndpoint()); + System.out.format("Deployed Model Id: %s\n", deployedModelRef.getDeployedModelId()); + } + + Status status = trainingPipelineResponse.getError(); + System.out.println("Error"); + System.out.format("Code: %s\n", status.getCode()); + System.out.format("Message: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_create_training_pipeline_image_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineImageObjectDetectionSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineImageObjectDetectionSample.java new file mode 100644 index 00000000000..65ade6ea4ad --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineImageObjectDetectionSample.java @@ -0,0 +1,210 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_image_object_detection_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.DeployedModelRef; +import com.google.cloud.aiplatform.v1.EnvVar; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.Model.ExportFormat; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.Port; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.PredictSchemata; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.cloud.aiplatform.v1beta1.schema.trainingjob.definition.AutoMlImageObjectDetectionInputs; +import com.google.cloud.aiplatform.v1beta1.schema.trainingjob.definition.AutoMlImageObjectDetectionInputs.ModelType; +import com.google.rpc.Status; +import java.io.IOException; + +public class CreateTrainingPipelineImageObjectDetectionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String trainingPipelineDisplayName = "YOUR_TRAINING_PIPELINE_DISPLAY_NAME"; + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String modelDisplayName = "YOUR_MODEL_DISPLAY_NAME"; + createTrainingPipelineImageObjectDetectionSample( + project, trainingPipelineDisplayName, datasetId, modelDisplayName); + } + + static void createTrainingPipelineImageObjectDetectionSample( + String project, String trainingPipelineDisplayName, String datasetId, String modelDisplayName) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + String trainingTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/" + + "automl_image_object_detection_1.0.0.yaml"; + LocationName locationName = LocationName.of(project, location); + + AutoMlImageObjectDetectionInputs autoMlImageObjectDetectionInputs = + AutoMlImageObjectDetectionInputs.newBuilder() + .setModelType(ModelType.CLOUD_HIGH_ACCURACY_1) + .setBudgetMilliNodeHours(20000) + .setDisableEarlyStopping(false) + .build(); + + InputDataConfig trainingInputDataConfig = + InputDataConfig.newBuilder().setDatasetId(datasetId).build(); + Model model = Model.newBuilder().setDisplayName(modelDisplayName).build(); + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(trainingPipelineDisplayName) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(ValueConverter.toValue(autoMlImageObjectDetectionInputs)) + .setInputDataConfig(trainingInputDataConfig) + .setModelToUpload(model) + .build(); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.createTrainingPipeline(locationName, trainingPipeline); + + System.out.println("Create Training Pipeline Image Object Detection Response"); + System.out.format("Name: %s\n", trainingPipelineResponse.getName()); + System.out.format("Display Name: %s\n", trainingPipelineResponse.getDisplayName()); + + System.out.format( + "Training Task Definition %s\n", trainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "Training Task Inputs: %s\n", trainingPipelineResponse.getTrainingTaskInputs()); + System.out.format( + "Training Task Metadata: %s\n", trainingPipelineResponse.getTrainingTaskMetadata()); + System.out.format("State: %s\n", trainingPipelineResponse.getState()); + + System.out.format("Create Time: %s\n", trainingPipelineResponse.getCreateTime()); + System.out.format("StartTime %s\n", trainingPipelineResponse.getStartTime()); + System.out.format("End Time: %s\n", trainingPipelineResponse.getEndTime()); + System.out.format("Update Time: %s\n", trainingPipelineResponse.getUpdateTime()); + System.out.format("Labels: %s\n", trainingPipelineResponse.getLabelsMap()); + + InputDataConfig inputDataConfig = trainingPipelineResponse.getInputDataConfig(); + System.out.println("Input Data Config"); + System.out.format("Dataset Id: %s", inputDataConfig.getDatasetId()); + System.out.format("Annotations Filter: %s\n", inputDataConfig.getAnnotationsFilter()); + + FractionSplit fractionSplit = inputDataConfig.getFractionSplit(); + System.out.println("Fraction Split"); + System.out.format("Training Fraction: %s\n", fractionSplit.getTrainingFraction()); + System.out.format("Validation Fraction: %s\n", fractionSplit.getValidationFraction()); + System.out.format("Test Fraction: %s\n", fractionSplit.getTestFraction()); + + FilterSplit filterSplit = inputDataConfig.getFilterSplit(); + System.out.println("Filter Split"); + System.out.format("Training Filter: %s\n", filterSplit.getTrainingFilter()); + System.out.format("Validation Filter: %s\n", filterSplit.getValidationFilter()); + System.out.format("Test Filter: %s\n", filterSplit.getTestFilter()); + + PredefinedSplit predefinedSplit = inputDataConfig.getPredefinedSplit(); + System.out.println("Predefined Split"); + System.out.format("Key: %s\n", predefinedSplit.getKey()); + + TimestampSplit timestampSplit = inputDataConfig.getTimestampSplit(); + System.out.println("Timestamp Split"); + System.out.format("Training Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("Validation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("Test Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("Key: %s\n", timestampSplit.getKey()); + + Model modelResponse = trainingPipelineResponse.getModelToUpload(); + System.out.println("Model To Upload"); + System.out.format("Name: %s\n", modelResponse.getName()); + System.out.format("Display Name: %s\n", modelResponse.getDisplayName()); + System.out.format("Description: %s\n", modelResponse.getDescription()); + + System.out.format("Metadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("Metadata: %s\n", modelResponse.getMetadata()); + System.out.format("Training Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("Artifact Uri: %s\n", modelResponse.getArtifactUri()); + + System.out.format( + "Supported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList()); + System.out.format( + "Supported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList()); + System.out.format( + "Supported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList()); + + System.out.format("Create Time: %s\n", modelResponse.getCreateTime()); + System.out.format("Update Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("Labels: %sn\n", modelResponse.getLabelsMap()); + + PredictSchemata predictSchemata = modelResponse.getPredictSchemata(); + System.out.println("Predict Schemata"); + System.out.format("Instance Schema Uri: %s\n", predictSchemata.getInstanceSchemaUri()); + System.out.format("Parameters Schema Uri: %s\n", predictSchemata.getParametersSchemaUri()); + System.out.format("Prediction Schema Uri: %s\n", predictSchemata.getPredictionSchemaUri()); + + for (ExportFormat exportFormat : modelResponse.getSupportedExportFormatsList()) { + System.out.println("Supported Export Format"); + System.out.format("Id: %s\n", exportFormat.getId()); + } + + ModelContainerSpec modelContainerSpec = modelResponse.getContainerSpec(); + System.out.println("Container Spec"); + System.out.format("Image Uri: %s\n", modelContainerSpec.getImageUri()); + System.out.format("Command: %s\n", modelContainerSpec.getCommandList()); + System.out.format("Args: %s\n", modelContainerSpec.getArgsList()); + System.out.format("Predict Route: %s\n", modelContainerSpec.getPredictRoute()); + System.out.format("Health Route: %s\n", modelContainerSpec.getHealthRoute()); + + for (EnvVar envVar : modelContainerSpec.getEnvList()) { + System.out.println("Env"); + System.out.format("Name: %s\n", envVar.getName()); + System.out.format("Value: %s\n", envVar.getValue()); + } + + for (Port port : modelContainerSpec.getPortsList()) { + System.out.println("Port"); + System.out.format("Container Port: %s\n", port.getContainerPort()); + } + + for (DeployedModelRef deployedModelRef : modelResponse.getDeployedModelsList()) { + System.out.println("Deployed Model"); + System.out.format("Endpoint: %s\n", deployedModelRef.getEndpoint()); + System.out.format("Deployed Model Id: %s\n", deployedModelRef.getDeployedModelId()); + } + + Status status = trainingPipelineResponse.getError(); + System.out.println("Error"); + System.out.format("Code: %s\n", status.getCode()); + System.out.format("Message: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_create_training_pipeline_image_object_detection_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineSample.java new file mode 100644 index 00000000000..33f94753e54 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineSample.java @@ -0,0 +1,210 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_sample] + +import com.google.cloud.aiplatform.v1.DeployedModelRef; +import com.google.cloud.aiplatform.v1.EnvVar; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.Model.ExportFormat; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.Port; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.PredictSchemata; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import com.google.rpc.Status; +import java.io.IOException; + +public class CreateTrainingPipelineSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String trainingPipelineDisplayName = "YOUR_TRAINING_PIPELINE_DISPLAY_NAME"; + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String trainingTaskDefinition = "YOUR_TRAINING_TASK_DEFINITION"; + String modelDisplayName = "YOUR_MODEL_DISPLAY_NAME"; + createTrainingPipelineSample( + project, trainingPipelineDisplayName, datasetId, trainingTaskDefinition, modelDisplayName); + } + + static void createTrainingPipelineSample( + String project, + String trainingPipelineDisplayName, + String datasetId, + String trainingTaskDefinition, + String modelDisplayName) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + + String jsonString = + "{\"multiLabel\": false, \"modelType\": \"CLOUD\", \"budgetMilliNodeHours\": 8000," + + " \"disableEarlyStopping\": false}"; + Value.Builder trainingTaskInputs = Value.newBuilder(); + JsonFormat.parser().merge(jsonString, trainingTaskInputs); + + InputDataConfig trainingInputDataConfig = + InputDataConfig.newBuilder().setDatasetId(datasetId).build(); + Model model = Model.newBuilder().setDisplayName(modelDisplayName).build(); + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(trainingPipelineDisplayName) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(trainingTaskInputs) + .setInputDataConfig(trainingInputDataConfig) + .setModelToUpload(model) + .build(); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.createTrainingPipeline(locationName, trainingPipeline); + + System.out.println("Create Training Pipeline Response"); + System.out.format("Name: %s\n", trainingPipelineResponse.getName()); + System.out.format("Display Name: %s\n", trainingPipelineResponse.getDisplayName()); + + System.out.format( + "Training Task Definition %s\n", trainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "Training Task Inputs: %s\n", trainingPipelineResponse.getTrainingTaskInputs()); + System.out.format( + "Training Task Metadata: %s\n", trainingPipelineResponse.getTrainingTaskMetadata()); + System.out.format("State: %s\n", trainingPipelineResponse.getState()); + + System.out.format("Create Time: %s\n", trainingPipelineResponse.getCreateTime()); + System.out.format("StartTime %s\n", trainingPipelineResponse.getStartTime()); + System.out.format("End Time: %s\n", trainingPipelineResponse.getEndTime()); + System.out.format("Update Time: %s\n", trainingPipelineResponse.getUpdateTime()); + System.out.format("Labels: %s\n", trainingPipelineResponse.getLabelsMap()); + + InputDataConfig inputDataConfig = trainingPipelineResponse.getInputDataConfig(); + System.out.println("Input Data Config"); + System.out.format("Dataset Id: %s", inputDataConfig.getDatasetId()); + System.out.format("Annotations Filter: %s\n", inputDataConfig.getAnnotationsFilter()); + + FractionSplit fractionSplit = inputDataConfig.getFractionSplit(); + System.out.println("Fraction Split"); + System.out.format("Training Fraction: %s\n", fractionSplit.getTrainingFraction()); + System.out.format("Validation Fraction: %s\n", fractionSplit.getValidationFraction()); + System.out.format("Test Fraction: %s\n", fractionSplit.getTestFraction()); + + FilterSplit filterSplit = inputDataConfig.getFilterSplit(); + System.out.println("Filter Split"); + System.out.format("Training Filter: %s\n", filterSplit.getTrainingFilter()); + System.out.format("Validation Filter: %s\n", filterSplit.getValidationFilter()); + System.out.format("Test Filter: %s\n", filterSplit.getTestFilter()); + + PredefinedSplit predefinedSplit = inputDataConfig.getPredefinedSplit(); + System.out.println("Predefined Split"); + System.out.format("Key: %s\n", predefinedSplit.getKey()); + + TimestampSplit timestampSplit = inputDataConfig.getTimestampSplit(); + System.out.println("Timestamp Split"); + System.out.format("Training Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("Validation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("Test Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("Key: %s\n", timestampSplit.getKey()); + + Model modelResponse = trainingPipelineResponse.getModelToUpload(); + System.out.println("Model To Upload"); + System.out.format("Name: %s\n", modelResponse.getName()); + System.out.format("Display Name: %s\n", modelResponse.getDisplayName()); + System.out.format("Description: %s\n", modelResponse.getDescription()); + + System.out.format("Metadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("Metadata: %s\n", modelResponse.getMetadata()); + System.out.format("Training Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("Artifact Uri: %s\n", modelResponse.getArtifactUri()); + + System.out.format( + "Supported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList()); + System.out.format( + "Supported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList()); + System.out.format( + "Supported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList()); + + System.out.format("Create Time: %s\n", modelResponse.getCreateTime()); + System.out.format("Update Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("Labels: %sn\n", modelResponse.getLabelsMap()); + + PredictSchemata predictSchemata = modelResponse.getPredictSchemata(); + System.out.println("Predict Schemata"); + System.out.format("Instance Schema Uri: %s\n", predictSchemata.getInstanceSchemaUri()); + System.out.format("Parameters Schema Uri: %s\n", predictSchemata.getParametersSchemaUri()); + System.out.format("Prediction Schema Uri: %s\n", predictSchemata.getPredictionSchemaUri()); + + for (ExportFormat exportFormat : modelResponse.getSupportedExportFormatsList()) { + System.out.println("Supported Export Format"); + System.out.format("Id: %s\n", exportFormat.getId()); + } + + ModelContainerSpec modelContainerSpec = modelResponse.getContainerSpec(); + System.out.println("Container Spec"); + System.out.format("Image Uri: %s\n", modelContainerSpec.getImageUri()); + System.out.format("Command: %s\n", modelContainerSpec.getCommandList()); + System.out.format("Args: %s\n", modelContainerSpec.getArgsList()); + System.out.format("Predict Route: %s\n", modelContainerSpec.getPredictRoute()); + System.out.format("Health Route: %s\n", modelContainerSpec.getHealthRoute()); + + for (EnvVar envVar : modelContainerSpec.getEnvList()) { + System.out.println("Env"); + System.out.format("Name: %s\n", envVar.getName()); + System.out.format("Value: %s\n", envVar.getValue()); + } + + for (Port port : modelContainerSpec.getPortsList()) { + System.out.println("Port"); + System.out.format("Container Port: %s\n", port.getContainerPort()); + } + + for (DeployedModelRef deployedModelRef : modelResponse.getDeployedModelsList()) { + System.out.println("Deployed Model"); + System.out.format("Endpoint: %s\n", deployedModelRef.getEndpoint()); + System.out.format("Deployed Model Id: %s\n", deployedModelRef.getDeployedModelId()); + } + + Status status = trainingPipelineResponse.getError(); + System.out.println("Error"); + System.out.format("Code: %s\n", status.getCode()); + System.out.format("Message: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_create_training_pipeline_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTabularClassificationSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTabularClassificationSample.java new file mode 100644 index 00000000000..107e8c01a4c --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTabularClassificationSample.java @@ -0,0 +1,249 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_tabular_classification_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.DeployedModelRef; +import com.google.cloud.aiplatform.v1.EnvVar; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.Port; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.PredictSchemata; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.cloud.aiplatform.v1.schema.trainingjob.definition.AutoMlTablesInputs; +import com.google.cloud.aiplatform.v1.schema.trainingjob.definition.AutoMlTablesInputs.Transformation; +import com.google.cloud.aiplatform.v1.schema.trainingjob.definition.AutoMlTablesInputs.Transformation.AutoTransformation; +import com.google.rpc.Status; +import java.io.IOException; +import java.util.ArrayList; + +public class CreateTrainingPipelineTabularClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String modelDisplayName = "YOUR_DATASET_DISPLAY_NAME"; + String datasetId = "YOUR_DATASET_ID"; + String targetColumn = "TARGET_COLUMN"; + createTrainingPipelineTableClassification(project, modelDisplayName, datasetId, targetColumn); + } + + static void createTrainingPipelineTableClassification( + String project, String modelDisplayName, String datasetId, String targetColumn) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + String trainingTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_tables_1.0.0.yaml"; + + // Set the columns used for training and their data types + Transformation transformation1 = + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("sepal_width").build()) + .build(); + Transformation transformation2 = + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("sepal_length").build()) + .build(); + Transformation transformation3 = + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("petal_length").build()) + .build(); + Transformation transformation4 = + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("petal_width").build()) + .build(); + + ArrayList transformationArrayList = new ArrayList<>(); + transformationArrayList.add(transformation1); + transformationArrayList.add(transformation2); + transformationArrayList.add(transformation3); + transformationArrayList.add(transformation4); + + AutoMlTablesInputs autoMlTablesInputs = + AutoMlTablesInputs.newBuilder() + .setTargetColumn(targetColumn) + .setPredictionType("classification") + .addAllTransformations(transformationArrayList) + .setTrainBudgetMilliNodeHours(8000) + .build(); + + FractionSplit fractionSplit = + FractionSplit.newBuilder() + .setTrainingFraction(0.8) + .setValidationFraction(0.1) + .setTestFraction(0.1) + .build(); + + InputDataConfig inputDataConfig = + InputDataConfig.newBuilder() + .setDatasetId(datasetId) + .setFractionSplit(fractionSplit) + .build(); + Model modelToUpload = Model.newBuilder().setDisplayName(modelDisplayName).build(); + + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(modelDisplayName) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(ValueConverter.toValue(autoMlTablesInputs)) + .setInputDataConfig(inputDataConfig) + .setModelToUpload(modelToUpload) + .build(); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.createTrainingPipeline(locationName, trainingPipeline); + + System.out.println("Create Training Pipeline Tabular Classification Response"); + System.out.format("\tName: %s\n", trainingPipelineResponse.getName()); + System.out.format("\tDisplay Name: %s\n", trainingPipelineResponse.getDisplayName()); + System.out.format( + "\tTraining Task Definition: %s\n", trainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "\tTraining Task Inputs: %s\n", trainingPipelineResponse.getTrainingTaskInputs()); + System.out.format( + "\tTraining Task Metadata: %s\n", trainingPipelineResponse.getTrainingTaskMetadata()); + + System.out.format("\tState: %s\n", trainingPipelineResponse.getState()); + System.out.format("\tCreate Time: %s\n", trainingPipelineResponse.getCreateTime()); + System.out.format("\tStart Time: %s\n", trainingPipelineResponse.getStartTime()); + System.out.format("\tEnd Time: %s\n", trainingPipelineResponse.getEndTime()); + System.out.format("\tUpdate Time: %s\n", trainingPipelineResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", trainingPipelineResponse.getLabelsMap()); + + InputDataConfig inputDataConfigResponse = trainingPipelineResponse.getInputDataConfig(); + System.out.println("\tInput Data Config"); + System.out.format("\t\tDataset Id: %s\n", inputDataConfigResponse.getDatasetId()); + System.out.format( + "\t\tAnnotations Filter: %s\n", inputDataConfigResponse.getAnnotationsFilter()); + + FractionSplit fractionSplitResponse = inputDataConfigResponse.getFractionSplit(); + System.out.println("\t\tFraction Split"); + System.out.format( + "\t\t\tTraining Fraction: %s\n", fractionSplitResponse.getTrainingFraction()); + System.out.format( + "\t\t\tValidation Fraction: %s\n", fractionSplitResponse.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", fractionSplitResponse.getTestFraction()); + + FilterSplit filterSplit = inputDataConfigResponse.getFilterSplit(); + System.out.println("\t\tFilter Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", filterSplit.getTrainingFilter()); + System.out.format("\t\t\tValidation Fraction: %s\n", filterSplit.getValidationFilter()); + System.out.format("\t\t\tTest Fraction: %s\n", filterSplit.getTestFilter()); + + PredefinedSplit predefinedSplit = inputDataConfigResponse.getPredefinedSplit(); + System.out.println("\t\tPredefined Split"); + System.out.format("\t\t\tKey: %s\n", predefinedSplit.getKey()); + + TimestampSplit timestampSplit = inputDataConfigResponse.getTimestampSplit(); + System.out.println("\t\tTimestamp Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("\t\t\tKey: %s\n", timestampSplit.getKey()); + + Model modelResponse = trainingPipelineResponse.getModelToUpload(); + System.out.println("\tModel To Upload"); + System.out.format("\t\tName: %s\n", modelResponse.getName()); + System.out.format("\t\tDisplay Name: %s\n", modelResponse.getDisplayName()); + System.out.format("\t\tDescription: %s\n", modelResponse.getDescription()); + System.out.format("\t\tMetadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("\t\tMeta Data: %s\n", modelResponse.getMetadata()); + System.out.format("\t\tTraining Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("\t\tArtifact Uri: %s\n", modelResponse.getArtifactUri()); + + System.out.format( + "\t\tSupported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList().toString()); + System.out.format( + "\t\tSupported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList().toString()); + System.out.format( + "\t\tSupported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList().toString()); + + System.out.format("\t\tCreate Time: %s\n", modelResponse.getCreateTime()); + System.out.format("\t\tUpdate Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("\t\tLables: %s\n", modelResponse.getLabelsMap()); + PredictSchemata predictSchemata = modelResponse.getPredictSchemata(); + + System.out.println("\tPredict Schemata"); + System.out.format("\t\tInstance Schema Uri: %s\n", predictSchemata.getInstanceSchemaUri()); + System.out.format( + "\t\tParameters Schema Uri: %s\n", predictSchemata.getParametersSchemaUri()); + System.out.format( + "\t\tPrediction Schema Uri: %s\n", predictSchemata.getPredictionSchemaUri()); + + for (Model.ExportFormat supportedExportFormat : + modelResponse.getSupportedExportFormatsList()) { + System.out.println("\tSupported Export Format"); + System.out.format("\t\tId: %s\n", supportedExportFormat.getId()); + } + ModelContainerSpec containerSpec = modelResponse.getContainerSpec(); + + System.out.println("\tContainer Spec"); + System.out.format("\t\tImage Uri: %s\n", containerSpec.getImageUri()); + System.out.format("\t\tCommand: %s\n", containerSpec.getCommandList()); + System.out.format("\t\tArgs: %s\n", containerSpec.getArgsList()); + System.out.format("\t\tPredict Route: %s\n", containerSpec.getPredictRoute()); + System.out.format("\t\tHealth Route: %s\n", containerSpec.getHealthRoute()); + + for (EnvVar envVar : containerSpec.getEnvList()) { + System.out.println("\t\tEnv"); + System.out.format("\t\t\tName: %s\n", envVar.getName()); + System.out.format("\t\t\tValue: %s\n", envVar.getValue()); + } + + for (Port port : containerSpec.getPortsList()) { + System.out.println("\t\tPort"); + System.out.format("\t\t\tContainer Port: %s\n", port.getContainerPort()); + } + + for (DeployedModelRef deployedModelRef : modelResponse.getDeployedModelsList()) { + System.out.println("\tDeployed Model"); + System.out.format("\t\tEndpoint: %s\n", deployedModelRef.getEndpoint()); + System.out.format("\t\tDeployed Model Id: %s\n", deployedModelRef.getDeployedModelId()); + } + + Status status = trainingPipelineResponse.getError(); + System.out.println("\tError"); + System.out.format("\t\tCode: %s\n", status.getCode()); + System.out.format("\t\tMessage: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_create_training_pipeline_tabular_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTabularRegressionSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTabularRegressionSample.java new file mode 100644 index 00000000000..427dae0c0cd --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTabularRegressionSample.java @@ -0,0 +1,321 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_tabular_regression_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.DeployedModelRef; +import com.google.cloud.aiplatform.v1.EnvVar; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.Port; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.PredictSchemata; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.cloud.aiplatform.v1beta1.schema.trainingjob.definition.AutoMlTablesInputs; +import com.google.cloud.aiplatform.v1beta1.schema.trainingjob.definition.AutoMlTablesInputs.Transformation; +import com.google.cloud.aiplatform.v1beta1.schema.trainingjob.definition.AutoMlTablesInputs.Transformation.AutoTransformation; +import com.google.cloud.aiplatform.v1beta1.schema.trainingjob.definition.AutoMlTablesInputs.Transformation.TimestampTransformation; +import com.google.rpc.Status; +import java.io.IOException; +import java.util.ArrayList; + +public class CreateTrainingPipelineTabularRegressionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String modelDisplayName = "YOUR_DATASET_DISPLAY_NAME"; + String datasetId = "YOUR_DATASET_ID"; + String targetColumn = "TARGET_COLUMN"; + createTrainingPipelineTableRegression(project, modelDisplayName, datasetId, targetColumn); + } + + static void createTrainingPipelineTableRegression( + String project, String modelDisplayName, String datasetId, String targetColumn) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + String trainingTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/automl_tables_1.0.0.yaml"; + + // Set the columns used for training and their data types + ArrayList tranformations = new ArrayList<>(); + tranformations.add( + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("STRING_5000unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("INTEGER_5000unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("FLOAT_5000unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("FLOAT_5000unique_REPEATED")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("NUMERIC_5000unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("BOOLEAN_2unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setTimestamp( + TimestampTransformation.newBuilder() + .setColumnName("TIMESTAMP_1unique_NULLABLE") + .setInvalidValuesAllowed(true)) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("DATE_1unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto(AutoTransformation.newBuilder().setColumnName("TIME_1unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setTimestamp( + TimestampTransformation.newBuilder() + .setColumnName("DATETIME_1unique_NULLABLE") + .setInvalidValuesAllowed(true)) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto( + AutoTransformation.newBuilder() + .setColumnName("STRUCT_NULLABLE.STRING_5000unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto( + AutoTransformation.newBuilder() + .setColumnName("STRUCT_NULLABLE.INTEGER_5000unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto( + AutoTransformation.newBuilder() + .setColumnName("STRUCT_NULLABLE.FLOAT_5000unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto( + AutoTransformation.newBuilder() + .setColumnName("STRUCT_NULLABLE.FLOAT_5000unique_REQUIRED")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto( + AutoTransformation.newBuilder() + .setColumnName("STRUCT_NULLABLE.FLOAT_5000unique_REPEATED")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto( + AutoTransformation.newBuilder() + .setColumnName("STRUCT_NULLABLE.NUMERIC_5000unique_NULLABLE")) + .build()); + tranformations.add( + Transformation.newBuilder() + .setAuto( + AutoTransformation.newBuilder() + .setColumnName("STRUCT_NULLABLE.TIMESTAMP_1unique_NULLABLE")) + .build()); + + AutoMlTablesInputs trainingTaskInputs = + AutoMlTablesInputs.newBuilder() + .addAllTransformations(tranformations) + .setTargetColumn(targetColumn) + .setPredictionType("regression") + .setTrainBudgetMilliNodeHours(8000) + .setDisableEarlyStopping(false) + // supported regression optimisation objectives: minimize-rmse, + // minimize-mae, minimize-rmsle + .setOptimizationObjective("minimize-rmse") + .build(); + + FractionSplit fractionSplit = + FractionSplit.newBuilder() + .setTrainingFraction(0.8) + .setValidationFraction(0.1) + .setTestFraction(0.1) + .build(); + + InputDataConfig inputDataConfig = + InputDataConfig.newBuilder() + .setDatasetId(datasetId) + .setFractionSplit(fractionSplit) + .build(); + Model modelToUpload = Model.newBuilder().setDisplayName(modelDisplayName).build(); + + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(modelDisplayName) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(ValueConverter.toValue(trainingTaskInputs)) + .setInputDataConfig(inputDataConfig) + .setModelToUpload(modelToUpload) + .build(); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.createTrainingPipeline(locationName, trainingPipeline); + + System.out.println("Create Training Pipeline Tabular Regression Response"); + System.out.format("\tName: %s\n", trainingPipelineResponse.getName()); + System.out.format("\tDisplay Name: %s\n", trainingPipelineResponse.getDisplayName()); + System.out.format( + "\tTraining Task Definition: %s\n", trainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "\tTraining Task Inputs: %s\n", trainingPipelineResponse.getTrainingTaskInputs()); + System.out.format( + "\tTraining Task Metadata: %s\n", trainingPipelineResponse.getTrainingTaskMetadata()); + + System.out.format("\tState: %s\n", trainingPipelineResponse.getState()); + System.out.format("\tCreate Time: %s\n", trainingPipelineResponse.getCreateTime()); + System.out.format("\tStart Time: %s\n", trainingPipelineResponse.getStartTime()); + System.out.format("\tEnd Time: %s\n", trainingPipelineResponse.getEndTime()); + System.out.format("\tUpdate Time: %s\n", trainingPipelineResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", trainingPipelineResponse.getLabelsMap()); + + InputDataConfig inputDataConfigResponse = trainingPipelineResponse.getInputDataConfig(); + System.out.println("\tInput Data Config"); + System.out.format("\t\tDataset Id: %s\n", inputDataConfigResponse.getDatasetId()); + System.out.format( + "\t\tAnnotations Filter: %s\n", inputDataConfigResponse.getAnnotationsFilter()); + + FractionSplit fractionSplitResponse = inputDataConfigResponse.getFractionSplit(); + System.out.println("\t\tFraction Split"); + System.out.format( + "\t\t\tTraining Fraction: %s\n", fractionSplitResponse.getTrainingFraction()); + System.out.format( + "\t\t\tValidation Fraction: %s\n", fractionSplitResponse.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", fractionSplitResponse.getTestFraction()); + + FilterSplit filterSplit = inputDataConfigResponse.getFilterSplit(); + System.out.println("\t\tFilter Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", filterSplit.getTrainingFilter()); + System.out.format("\t\t\tValidation Fraction: %s\n", filterSplit.getValidationFilter()); + System.out.format("\t\t\tTest Fraction: %s\n", filterSplit.getTestFilter()); + + PredefinedSplit predefinedSplit = inputDataConfigResponse.getPredefinedSplit(); + System.out.println("\t\tPredefined Split"); + System.out.format("\t\t\tKey: %s\n", predefinedSplit.getKey()); + + TimestampSplit timestampSplit = inputDataConfigResponse.getTimestampSplit(); + System.out.println("\t\tTimestamp Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("\t\t\tKey: %s\n", timestampSplit.getKey()); + + Model modelResponse = trainingPipelineResponse.getModelToUpload(); + System.out.println("\tModel To Upload"); + System.out.format("\t\tName: %s\n", modelResponse.getName()); + System.out.format("\t\tDisplay Name: %s\n", modelResponse.getDisplayName()); + System.out.format("\t\tDescription: %s\n", modelResponse.getDescription()); + System.out.format("\t\tMetadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("\t\tMeta Data: %s\n", modelResponse.getMetadata()); + System.out.format("\t\tTraining Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("\t\tArtifact Uri: %s\n", modelResponse.getArtifactUri()); + + System.out.format( + "\t\tSupported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList().toString()); + System.out.format( + "\t\tSupported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList().toString()); + System.out.format( + "\t\tSupported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList().toString()); + + System.out.format("\t\tCreate Time: %s\n", modelResponse.getCreateTime()); + System.out.format("\t\tUpdate Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("\t\tLables: %s\n", modelResponse.getLabelsMap()); + PredictSchemata predictSchemata = modelResponse.getPredictSchemata(); + + System.out.println("\tPredict Schemata"); + System.out.format("\t\tInstance Schema Uri: %s\n", predictSchemata.getInstanceSchemaUri()); + System.out.format( + "\t\tParameters Schema Uri: %s\n", predictSchemata.getParametersSchemaUri()); + System.out.format( + "\t\tPrediction Schema Uri: %s\n", predictSchemata.getPredictionSchemaUri()); + + for (Model.ExportFormat supportedExportFormat : + modelResponse.getSupportedExportFormatsList()) { + System.out.println("\tSupported Export Format"); + System.out.format("\t\tId: %s\n", supportedExportFormat.getId()); + } + ModelContainerSpec containerSpec = modelResponse.getContainerSpec(); + + System.out.println("\tContainer Spec"); + System.out.format("\t\tImage Uri: %s\n", containerSpec.getImageUri()); + System.out.format("\t\tCommand: %s\n", containerSpec.getCommandList()); + System.out.format("\t\tArgs: %s\n", containerSpec.getArgsList()); + System.out.format("\t\tPredict Route: %s\n", containerSpec.getPredictRoute()); + System.out.format("\t\tHealth Route: %s\n", containerSpec.getHealthRoute()); + + for (EnvVar envVar : containerSpec.getEnvList()) { + System.out.println("\t\tEnv"); + System.out.format("\t\t\tName: %s\n", envVar.getName()); + System.out.format("\t\t\tValue: %s\n", envVar.getValue()); + } + + for (Port port : containerSpec.getPortsList()) { + System.out.println("\t\tPort"); + System.out.format("\t\t\tContainer Port: %s\n", port.getContainerPort()); + } + + for (DeployedModelRef deployedModelRef : modelResponse.getDeployedModelsList()) { + System.out.println("\tDeployed Model"); + System.out.format("\t\tEndpoint: %s\n", deployedModelRef.getEndpoint()); + System.out.format("\t\tDeployed Model Id: %s\n", deployedModelRef.getDeployedModelId()); + } + + Status status = trainingPipelineResponse.getError(); + System.out.println("\tError"); + System.out.format("\t\tCode: %s\n", status.getCode()); + System.out.format("\t\tMessage: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_create_training_pipeline_tabular_regression_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextClassificationSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextClassificationSample.java new file mode 100644 index 00000000000..ac338beb37c --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextClassificationSample.java @@ -0,0 +1,209 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_text_classification_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.DeployedModelRef; +import com.google.cloud.aiplatform.v1.EnvVar; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.Model.ExportFormat; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.Port; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.PredictSchemata; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.cloud.aiplatform.v1beta1.schema.trainingjob.definition.AutoMlTextClassificationInputs; +import com.google.rpc.Status; +import java.io.IOException; + +public class CreateTrainingPipelineTextClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String trainingPipelineDisplayName = "YOUR_TRAINING_PIPELINE_DISPLAY_NAME"; + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String modelDisplayName = "YOUR_MODEL_DISPLAY_NAME"; + + createTrainingPipelineTextClassificationSample( + project, trainingPipelineDisplayName, datasetId, modelDisplayName); + } + + static void createTrainingPipelineTextClassificationSample( + String project, String trainingPipelineDisplayName, String datasetId, String modelDisplayName) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + String trainingTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/" + + "automl_text_classification_1.0.0.yaml"; + + LocationName locationName = LocationName.of(project, location); + + AutoMlTextClassificationInputs trainingTaskInputs = + AutoMlTextClassificationInputs.newBuilder().setMultiLabel(false).build(); + + InputDataConfig trainingInputDataConfig = + InputDataConfig.newBuilder().setDatasetId(datasetId).build(); + Model model = Model.newBuilder().setDisplayName(modelDisplayName).build(); + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(trainingPipelineDisplayName) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(ValueConverter.toValue(trainingTaskInputs)) + .setInputDataConfig(trainingInputDataConfig) + .setModelToUpload(model) + .build(); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.createTrainingPipeline(locationName, trainingPipeline); + + System.out.println("Create Training Pipeline Text Classification Response"); + System.out.format("\tName: %s\n", trainingPipelineResponse.getName()); + System.out.format("\tDisplay Name: %s\n", trainingPipelineResponse.getDisplayName()); + + System.out.format( + "\tTraining Task Definition %s\n", trainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "\tTraining Task Inputs: %s\n", trainingPipelineResponse.getTrainingTaskInputs()); + System.out.format( + "\tTraining Task Metadata: %s\n", trainingPipelineResponse.getTrainingTaskMetadata()); + System.out.format("State: %s\n", trainingPipelineResponse.getState()); + + System.out.format("\tCreate Time: %s\n", trainingPipelineResponse.getCreateTime()); + System.out.format("\tStartTime %s\n", trainingPipelineResponse.getStartTime()); + System.out.format("\tEnd Time: %s\n", trainingPipelineResponse.getEndTime()); + System.out.format("\tUpdate Time: %s\n", trainingPipelineResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", trainingPipelineResponse.getLabelsMap()); + + InputDataConfig inputDataConfig = trainingPipelineResponse.getInputDataConfig(); + System.out.println("\tInput Data Config"); + System.out.format("\t\tDataset Id: %s", inputDataConfig.getDatasetId()); + System.out.format("\t\tAnnotations Filter: %s\n", inputDataConfig.getAnnotationsFilter()); + + FractionSplit fractionSplit = inputDataConfig.getFractionSplit(); + System.out.println("\t\tFraction Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", fractionSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", fractionSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", fractionSplit.getTestFraction()); + + FilterSplit filterSplit = inputDataConfig.getFilterSplit(); + System.out.println("\t\tFilter Split"); + System.out.format("\t\t\tTraining Filter: %s\n", filterSplit.getTrainingFilter()); + System.out.format("\t\t\tValidation Filter: %s\n", filterSplit.getValidationFilter()); + System.out.format("\t\t\tTest Filter: %s\n", filterSplit.getTestFilter()); + + PredefinedSplit predefinedSplit = inputDataConfig.getPredefinedSplit(); + System.out.println("\t\tPredefined Split"); + System.out.format("\t\t\tKey: %s\n", predefinedSplit.getKey()); + + TimestampSplit timestampSplit = inputDataConfig.getTimestampSplit(); + System.out.println("\t\tTimestamp Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("\t\t\tKey: %s\n", timestampSplit.getKey()); + + Model modelResponse = trainingPipelineResponse.getModelToUpload(); + System.out.println("\tModel To Upload"); + System.out.format("\t\tName: %s\n", modelResponse.getName()); + System.out.format("\t\tDisplay Name: %s\n", modelResponse.getDisplayName()); + System.out.format("\t\tDescription: %s\n", modelResponse.getDescription()); + + System.out.format("\t\tMetadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("\t\tMetadata: %s\n", modelResponse.getMetadata()); + System.out.format("\t\tTraining Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("\t\tArtifact Uri: %s\n", modelResponse.getArtifactUri()); + + System.out.format( + "\t\tSupported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList()); + System.out.format( + "\t\tSupported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList()); + System.out.format( + "\t\tSupported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList()); + + System.out.format("\t\tCreate Time: %s\n", modelResponse.getCreateTime()); + System.out.format("\t\tUpdate Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("\t\tLabels: %sn\n", modelResponse.getLabelsMap()); + + PredictSchemata predictSchemata = modelResponse.getPredictSchemata(); + System.out.println("\t\tPredict Schemata"); + System.out.format("\t\t\tInstance Schema Uri: %s\n", predictSchemata.getInstanceSchemaUri()); + System.out.format( + "\t\t\tParameters Schema Uri: %s\n", predictSchemata.getParametersSchemaUri()); + System.out.format( + "\t\t\tPrediction Schema Uri: %s\n", predictSchemata.getPredictionSchemaUri()); + + for (ExportFormat exportFormat : modelResponse.getSupportedExportFormatsList()) { + System.out.println("\t\tSupported Export Format"); + System.out.format("\t\t\tId: %s\n", exportFormat.getId()); + } + + ModelContainerSpec modelContainerSpec = modelResponse.getContainerSpec(); + System.out.println("\t\tContainer Spec"); + System.out.format("\t\t\tImage Uri: %s\n", modelContainerSpec.getImageUri()); + System.out.format("\t\t\tCommand: %s\n", modelContainerSpec.getCommandList()); + System.out.format("\t\t\tArgs: %s\n", modelContainerSpec.getArgsList()); + System.out.format("\t\t\tPredict Route: %s\n", modelContainerSpec.getPredictRoute()); + System.out.format("\t\t\tHealth Route: %s\n", modelContainerSpec.getHealthRoute()); + + for (EnvVar envVar : modelContainerSpec.getEnvList()) { + System.out.println("\t\t\tEnv"); + System.out.format("\t\t\t\tName: %s\n", envVar.getName()); + System.out.format("\t\t\t\tValue: %s\n", envVar.getValue()); + } + + for (Port port : modelContainerSpec.getPortsList()) { + System.out.println("\t\t\tPort"); + System.out.format("\t\t\t\tContainer Port: %s\n", port.getContainerPort()); + } + + for (DeployedModelRef deployedModelRef : modelResponse.getDeployedModelsList()) { + System.out.println("\t\tDeployed Model"); + System.out.format("\t\t\tEndpoint: %s\n", deployedModelRef.getEndpoint()); + System.out.format("\t\t\tDeployed Model Id: %s\n", deployedModelRef.getDeployedModelId()); + } + + Status status = trainingPipelineResponse.getError(); + System.out.println("\tError"); + System.out.format("\t\tCode: %s\n", status.getCode()); + System.out.format("\t\tMessage: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_create_training_pipeline_text_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextEntityExtractionSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextEntityExtractionSample.java new file mode 100644 index 00000000000..63dc1348461 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextEntityExtractionSample.java @@ -0,0 +1,205 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_text_entity_extraction_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.DeployedModelRef; +import com.google.cloud.aiplatform.v1.EnvVar; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.Model.ExportFormat; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.Port; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.PredictSchemata; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.rpc.Status; +import java.io.IOException; + +public class CreateTrainingPipelineTextEntityExtractionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String trainingPipelineDisplayName = "YOUR_TRAINING_PIPELINE_DISPLAY_NAME"; + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String modelDisplayName = "YOUR_MODEL_DISPLAY_NAME"; + + createTrainingPipelineTextEntityExtractionSample( + project, trainingPipelineDisplayName, datasetId, modelDisplayName); + } + + static void createTrainingPipelineTextEntityExtractionSample( + String project, String trainingPipelineDisplayName, String datasetId, String modelDisplayName) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + String trainingTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/" + + "automl_text_extraction_1.0.0.yaml"; + + LocationName locationName = LocationName.of(project, location); + + InputDataConfig trainingInputDataConfig = + InputDataConfig.newBuilder().setDatasetId(datasetId).build(); + Model model = Model.newBuilder().setDisplayName(modelDisplayName).build(); + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(trainingPipelineDisplayName) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(ValueConverter.EMPTY_VALUE) + .setInputDataConfig(trainingInputDataConfig) + .setModelToUpload(model) + .build(); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.createTrainingPipeline(locationName, trainingPipeline); + + System.out.println("Create Training Pipeline Text Entity Extraction Response"); + System.out.format("\tName: %s\n", trainingPipelineResponse.getName()); + System.out.format("\tDisplay Name: %s\n", trainingPipelineResponse.getDisplayName()); + + System.out.format( + "\tTraining Task Definition %s\n", trainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "\tTraining Task Inputs: %s\n", trainingPipelineResponse.getTrainingTaskInputs()); + System.out.format( + "\tTraining Task Metadata: %s\n", trainingPipelineResponse.getTrainingTaskMetadata()); + System.out.format("State: %s\n", trainingPipelineResponse.getState()); + + System.out.format("\tCreate Time: %s\n", trainingPipelineResponse.getCreateTime()); + System.out.format("\tStartTime %s\n", trainingPipelineResponse.getStartTime()); + System.out.format("\tEnd Time: %s\n", trainingPipelineResponse.getEndTime()); + System.out.format("\tUpdate Time: %s\n", trainingPipelineResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", trainingPipelineResponse.getLabelsMap()); + + InputDataConfig inputDataConfig = trainingPipelineResponse.getInputDataConfig(); + System.out.println("\tInput Data Config"); + System.out.format("\t\tDataset Id: %s", inputDataConfig.getDatasetId()); + System.out.format("\t\tAnnotations Filter: %s\n", inputDataConfig.getAnnotationsFilter()); + + FractionSplit fractionSplit = inputDataConfig.getFractionSplit(); + System.out.println("\t\tFraction Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", fractionSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", fractionSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", fractionSplit.getTestFraction()); + + FilterSplit filterSplit = inputDataConfig.getFilterSplit(); + System.out.println("\t\tFilter Split"); + System.out.format("\t\t\tTraining Filter: %s\n", filterSplit.getTrainingFilter()); + System.out.format("\t\t\tValidation Filter: %s\n", filterSplit.getValidationFilter()); + System.out.format("\t\t\tTest Filter: %s\n", filterSplit.getTestFilter()); + + PredefinedSplit predefinedSplit = inputDataConfig.getPredefinedSplit(); + System.out.println("\t\tPredefined Split"); + System.out.format("\t\t\tKey: %s\n", predefinedSplit.getKey()); + + TimestampSplit timestampSplit = inputDataConfig.getTimestampSplit(); + System.out.println("\t\tTimestamp Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("\t\t\tKey: %s\n", timestampSplit.getKey()); + + Model modelResponse = trainingPipelineResponse.getModelToUpload(); + System.out.println("\tModel To Upload"); + System.out.format("\t\tName: %s\n", modelResponse.getName()); + System.out.format("\t\tDisplay Name: %s\n", modelResponse.getDisplayName()); + System.out.format("\t\tDescription: %s\n", modelResponse.getDescription()); + + System.out.format("\t\tMetadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("\t\tMetadata: %s\n", modelResponse.getMetadata()); + System.out.format("\t\tTraining Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("\t\tArtifact Uri: %s\n", modelResponse.getArtifactUri()); + + System.out.format( + "\t\tSupported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList()); + System.out.format( + "\t\tSupported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList()); + System.out.format( + "\t\tSupported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList()); + + System.out.format("\t\tCreate Time: %s\n", modelResponse.getCreateTime()); + System.out.format("\t\tUpdate Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("\t\tLabels: %sn\n", modelResponse.getLabelsMap()); + + PredictSchemata predictSchemata = modelResponse.getPredictSchemata(); + System.out.println("\t\tPredict Schemata"); + System.out.format("\t\t\tInstance Schema Uri: %s\n", predictSchemata.getInstanceSchemaUri()); + System.out.format( + "\t\t\tParameters Schema Uri: %s\n", predictSchemata.getParametersSchemaUri()); + System.out.format( + "\t\t\tPrediction Schema Uri: %s\n", predictSchemata.getPredictionSchemaUri()); + + for (ExportFormat exportFormat : modelResponse.getSupportedExportFormatsList()) { + System.out.println("\t\tSupported Export Format"); + System.out.format("\t\t\tId: %s\n", exportFormat.getId()); + } + + ModelContainerSpec modelContainerSpec = modelResponse.getContainerSpec(); + System.out.println("\t\tContainer Spec"); + System.out.format("\t\t\tImage Uri: %s\n", modelContainerSpec.getImageUri()); + System.out.format("\t\t\tCommand: %s\n", modelContainerSpec.getCommandList()); + System.out.format("\t\t\tArgs: %s\n", modelContainerSpec.getArgsList()); + System.out.format("\t\t\tPredict Route: %s\n", modelContainerSpec.getPredictRoute()); + System.out.format("\t\t\tHealth Route: %s\n", modelContainerSpec.getHealthRoute()); + + for (EnvVar envVar : modelContainerSpec.getEnvList()) { + System.out.println("\t\t\tEnv"); + System.out.format("\t\t\t\tName: %s\n", envVar.getName()); + System.out.format("\t\t\t\tValue: %s\n", envVar.getValue()); + } + + for (Port port : modelContainerSpec.getPortsList()) { + System.out.println("\t\t\tPort"); + System.out.format("\t\t\t\tContainer Port: %s\n", port.getContainerPort()); + } + + for (DeployedModelRef deployedModelRef : modelResponse.getDeployedModelsList()) { + System.out.println("\t\tDeployed Model"); + System.out.format("\t\t\tEndpoint: %s\n", deployedModelRef.getEndpoint()); + System.out.format("\t\t\tDeployed Model Id: %s\n", deployedModelRef.getDeployedModelId()); + } + + Status status = trainingPipelineResponse.getError(); + System.out.println("\tError"); + System.out.format("\t\tCode: %s\n", status.getCode()); + System.out.format("\t\tMessage: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_create_training_pipeline_text_entity_extraction_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextSentimentAnalysisSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextSentimentAnalysisSample.java new file mode 100644 index 00000000000..ef87a9bfd2a --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineTextSentimentAnalysisSample.java @@ -0,0 +1,213 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_text_sentiment_analysis_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.DeployedModelRef; +import com.google.cloud.aiplatform.v1.EnvVar; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.Model.ExportFormat; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.Port; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.PredictSchemata; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.cloud.aiplatform.v1.schema.trainingjob.definition.AutoMlTextSentimentInputs; +import com.google.rpc.Status; +import java.io.IOException; + +public class CreateTrainingPipelineTextSentimentAnalysisSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String trainingPipelineDisplayName = "YOUR_TRAINING_PIPELINE_DISPLAY_NAME"; + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String modelDisplayName = "YOUR_MODEL_DISPLAY_NAME"; + + createTrainingPipelineTextSentimentAnalysisSample( + project, trainingPipelineDisplayName, datasetId, modelDisplayName); + } + + static void createTrainingPipelineTextSentimentAnalysisSample( + String project, String trainingPipelineDisplayName, String datasetId, String modelDisplayName) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + String trainingTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/" + + "automl_text_sentiment_1.0.0.yaml"; + + LocationName locationName = LocationName.of(project, location); + + AutoMlTextSentimentInputs trainingTaskInputs = + AutoMlTextSentimentInputs.newBuilder() + // Sentiment max must be between 1 and 10 inclusive. + // Higher value means positive sentiment. + .setSentimentMax(4) + .build(); + + InputDataConfig trainingInputDataConfig = + InputDataConfig.newBuilder().setDatasetId(datasetId).build(); + Model model = Model.newBuilder().setDisplayName(modelDisplayName).build(); + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(trainingPipelineDisplayName) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(ValueConverter.toValue(trainingTaskInputs)) + .setInputDataConfig(trainingInputDataConfig) + .setModelToUpload(model) + .build(); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.createTrainingPipeline(locationName, trainingPipeline); + + System.out.println("Create Training Pipeline Text Sentiment Analysis Response"); + System.out.format("\tName: %s\n", trainingPipelineResponse.getName()); + System.out.format("\tDisplay Name: %s\n", trainingPipelineResponse.getDisplayName()); + + System.out.format( + "\tTraining Task Definition %s\n", trainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "\tTraining Task Inputs: %s\n", trainingPipelineResponse.getTrainingTaskInputs()); + System.out.format( + "\tTraining Task Metadata: %s\n", trainingPipelineResponse.getTrainingTaskMetadata()); + System.out.format("State: %s\n", trainingPipelineResponse.getState()); + + System.out.format("\tCreate Time: %s\n", trainingPipelineResponse.getCreateTime()); + System.out.format("\tStartTime %s\n", trainingPipelineResponse.getStartTime()); + System.out.format("\tEnd Time: %s\n", trainingPipelineResponse.getEndTime()); + System.out.format("\tUpdate Time: %s\n", trainingPipelineResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", trainingPipelineResponse.getLabelsMap()); + + InputDataConfig inputDataConfig = trainingPipelineResponse.getInputDataConfig(); + System.out.println("\tInput Data Config"); + System.out.format("\t\tDataset Id: %s", inputDataConfig.getDatasetId()); + System.out.format("\t\tAnnotations Filter: %s\n", inputDataConfig.getAnnotationsFilter()); + + FractionSplit fractionSplit = inputDataConfig.getFractionSplit(); + System.out.println("\t\tFraction Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", fractionSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", fractionSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", fractionSplit.getTestFraction()); + + FilterSplit filterSplit = inputDataConfig.getFilterSplit(); + System.out.println("\t\tFilter Split"); + System.out.format("\t\t\tTraining Filter: %s\n", filterSplit.getTrainingFilter()); + System.out.format("\t\t\tValidation Filter: %s\n", filterSplit.getValidationFilter()); + System.out.format("\t\t\tTest Filter: %s\n", filterSplit.getTestFilter()); + + PredefinedSplit predefinedSplit = inputDataConfig.getPredefinedSplit(); + System.out.println("\t\tPredefined Split"); + System.out.format("\t\t\tKey: %s\n", predefinedSplit.getKey()); + + TimestampSplit timestampSplit = inputDataConfig.getTimestampSplit(); + System.out.println("\t\tTimestamp Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("\t\t\tKey: %s\n", timestampSplit.getKey()); + + Model modelResponse = trainingPipelineResponse.getModelToUpload(); + System.out.println("\tModel To Upload"); + System.out.format("\t\tName: %s\n", modelResponse.getName()); + System.out.format("\t\tDisplay Name: %s\n", modelResponse.getDisplayName()); + System.out.format("\t\tDescription: %s\n", modelResponse.getDescription()); + + System.out.format("\t\tMetadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("\t\tMetadata: %s\n", modelResponse.getMetadata()); + System.out.format("\t\tTraining Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("\t\tArtifact Uri: %s\n", modelResponse.getArtifactUri()); + + System.out.format( + "\t\tSupported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList()); + System.out.format( + "\t\tSupported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList()); + System.out.format( + "\t\tSupported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList()); + + System.out.format("\t\tCreate Time: %s\n", modelResponse.getCreateTime()); + System.out.format("\t\tUpdate Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("\t\tLabels: %sn\n", modelResponse.getLabelsMap()); + + PredictSchemata predictSchemata = modelResponse.getPredictSchemata(); + System.out.println("\t\tPredict Schemata"); + System.out.format("\t\t\tInstance Schema Uri: %s\n", predictSchemata.getInstanceSchemaUri()); + System.out.format( + "\t\t\tParameters Schema Uri: %s\n", predictSchemata.getParametersSchemaUri()); + System.out.format( + "\t\t\tPrediction Schema Uri: %s\n", predictSchemata.getPredictionSchemaUri()); + + for (ExportFormat exportFormat : modelResponse.getSupportedExportFormatsList()) { + System.out.println("\t\tSupported Export Format"); + System.out.format("\t\t\tId: %s\n", exportFormat.getId()); + } + + ModelContainerSpec modelContainerSpec = modelResponse.getContainerSpec(); + System.out.println("\t\tContainer Spec"); + System.out.format("\t\t\tImage Uri: %s\n", modelContainerSpec.getImageUri()); + System.out.format("\t\t\tCommand: %s\n", modelContainerSpec.getCommandList()); + System.out.format("\t\t\tArgs: %s\n", modelContainerSpec.getArgsList()); + System.out.format("\t\t\tPredict Route: %s\n", modelContainerSpec.getPredictRoute()); + System.out.format("\t\t\tHealth Route: %s\n", modelContainerSpec.getHealthRoute()); + + for (EnvVar envVar : modelContainerSpec.getEnvList()) { + System.out.println("\t\t\tEnv"); + System.out.format("\t\t\t\tName: %s\n", envVar.getName()); + System.out.format("\t\t\t\tValue: %s\n", envVar.getValue()); + } + + for (Port port : modelContainerSpec.getPortsList()) { + System.out.println("\t\t\tPort"); + System.out.format("\t\t\t\tContainer Port: %s\n", port.getContainerPort()); + } + + for (DeployedModelRef deployedModelRef : modelResponse.getDeployedModelsList()) { + System.out.println("\t\tDeployed Model"); + System.out.format("\t\t\tEndpoint: %s\n", deployedModelRef.getEndpoint()); + System.out.format("\t\t\tDeployed Model Id: %s\n", deployedModelRef.getDeployedModelId()); + } + + Status status = trainingPipelineResponse.getError(); + System.out.println("\tError"); + System.out.format("\t\tCode: %s\n", status.getCode()); + System.out.format("\t\tMessage: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_create_training_pipeline_text_sentiment_analysis_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoActionRecognitionSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoActionRecognitionSample.java new file mode 100644 index 00000000000..02e15fb5dac --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoActionRecognitionSample.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_video_action_recognition_sample] +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.cloud.aiplatform.v1.schema.trainingjob.definition.AutoMlVideoActionRecognitionInputs; +import com.google.cloud.aiplatform.v1.schema.trainingjob.definition.AutoMlVideoActionRecognitionInputs.ModelType; +import java.io.IOException; + +public class CreateTrainingPipelineVideoActionRecognitionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String displayName = "DISPLAY_NAME"; + String datasetId = "DATASET_ID"; + String modelDisplayName = "MODEL_DISPLAY_NAME"; + createTrainingPipelineVideoActionRecognitionSample( + project, displayName, datasetId, modelDisplayName); + } + + static void createTrainingPipelineVideoActionRecognitionSample( + String project, String displayName, String datasetId, String modelDisplayName) + throws IOException { + PipelineServiceSettings settings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient client = PipelineServiceClient.create(settings)) { + AutoMlVideoActionRecognitionInputs trainingTaskInputs = + AutoMlVideoActionRecognitionInputs.newBuilder().setModelType(ModelType.CLOUD).build(); + + InputDataConfig inputDataConfig = + InputDataConfig.newBuilder().setDatasetId(datasetId).build(); + Model modelToUpload = Model.newBuilder().setDisplayName(modelDisplayName).build(); + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(displayName) + .setTrainingTaskDefinition( + "gs://google-cloud-aiplatform/schema/trainingjob/definition/" + + "automl_video_action_recognition_1.0.0.yaml") + .setTrainingTaskInputs(ValueConverter.toValue(trainingTaskInputs)) + .setInputDataConfig(inputDataConfig) + .setModelToUpload(modelToUpload) + .build(); + LocationName parent = LocationName.of(project, location); + TrainingPipeline response = client.createTrainingPipeline(parent, trainingPipeline); + System.out.format("response: %s\n", response); + System.out.format("Name: %s\n", response.getName()); + } + } +} + +// [END aiplatform_create_training_pipeline_video_action_recognition_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoClassificationSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoClassificationSample.java new file mode 100644 index 00000000000..403476b24b9 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoClassificationSample.java @@ -0,0 +1,160 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_video_classification_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.rpc.Status; +import java.io.IOException; + +public class CreateTrainingPipelineVideoClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String videoClassificationDisplayName = + "YOUR_TRAINING_PIPELINE_VIDEO_CLASSIFICATION_DISPLAY_NAME"; + String datasetId = "YOUR_DATASET_ID"; + String modelDisplayName = "YOUR_MODEL_DISPLAY_NAME"; + String project = "YOUR_PROJECT_ID"; + createTrainingPipelineVideoClassification( + videoClassificationDisplayName, datasetId, modelDisplayName, project); + } + + static void createTrainingPipelineVideoClassification( + String videoClassificationDisplayName, + String datasetId, + String modelDisplayName, + String project) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + String trainingTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/" + + "automl_video_classification_1.0.0.yaml"; + + InputDataConfig inputDataConfig = + InputDataConfig.newBuilder().setDatasetId(datasetId).build(); + Model model = Model.newBuilder().setDisplayName(modelDisplayName).build(); + + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(videoClassificationDisplayName) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(ValueConverter.EMPTY_VALUE) + .setInputDataConfig(inputDataConfig) + .setModelToUpload(model) + .build(); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.createTrainingPipeline(locationName, trainingPipeline); + + System.out.println("Create Training Pipeline Video Classification Response"); + System.out.format("\tName: %s\n", trainingPipelineResponse.getName()); + System.out.format("\tDisplay Name: %s\n", trainingPipelineResponse.getDisplayName()); + System.out.format( + "\tTraining Task Definition: %s\n", trainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "\tTraining Task Inputs: %s\n", trainingPipelineResponse.getTrainingTaskInputs()); + System.out.format( + "\tTraining Task Metadata: %s\n", trainingPipelineResponse.getTrainingTaskMetadata()); + System.out.format("\tState: %s\n", trainingPipelineResponse.getState()); + System.out.format("\tCreate Time: %s\n", trainingPipelineResponse.getCreateTime()); + System.out.format("\tStart Time: %s\n", trainingPipelineResponse.getStartTime()); + System.out.format("\tEnd Time: %s\n", trainingPipelineResponse.getEndTime()); + System.out.format("\tUpdate Time: %s\n", trainingPipelineResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", trainingPipelineResponse.getLabelsMap()); + + InputDataConfig inputDataConfigResponse = trainingPipelineResponse.getInputDataConfig(); + System.out.println("\tInput Data Config"); + System.out.format("\t\tDataset Id: %s\n", inputDataConfigResponse.getDatasetId()); + System.out.format( + "\t\tAnnotations Filter: %s\n", inputDataConfigResponse.getAnnotationsFilter()); + + FractionSplit fractionSplit = inputDataConfigResponse.getFractionSplit(); + System.out.println("\t\tFraction Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", fractionSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", fractionSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", fractionSplit.getTestFraction()); + + FilterSplit filterSplit = inputDataConfigResponse.getFilterSplit(); + System.out.println("\t\tFilter Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", filterSplit.getTrainingFilter()); + System.out.format("\t\t\tValidation Fraction: %s\n", filterSplit.getValidationFilter()); + System.out.format("\t\t\tTest Fraction: %s\n", filterSplit.getTestFilter()); + + PredefinedSplit predefinedSplit = inputDataConfigResponse.getPredefinedSplit(); + System.out.println("\t\tPredefined Split"); + System.out.format("\t\t\tKey: %s\n", predefinedSplit.getKey()); + + TimestampSplit timestampSplit = inputDataConfigResponse.getTimestampSplit(); + System.out.println("\t\tTimestamp Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("\t\t\tKey: %s\n", timestampSplit.getKey()); + + Model modelResponse = trainingPipelineResponse.getModelToUpload(); + System.out.println("\tModel To Upload"); + System.out.format("\t\tName: %s\n", modelResponse.getName()); + System.out.format("\t\tDisplay Name: %s\n", modelResponse.getDisplayName()); + System.out.format("\t\tDescription: %s\n", modelResponse.getDescription()); + System.out.format("\t\tMetadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("\t\tMeta Data: %s\n", modelResponse.getMetadata()); + System.out.format("\t\tTraining Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("\t\tArtifact Uri: %s\n", modelResponse.getArtifactUri()); + System.out.format( + "\t\tSupported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList().toString()); + System.out.format( + "\t\tSupported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList().toString()); + System.out.format( + "\t\tSupported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList().toString()); + System.out.format("\t\tCreate Time: %s\n", modelResponse.getCreateTime()); + System.out.format("\t\tUpdate Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("\t\tLables: %s\n", modelResponse.getLabelsMap()); + + Status status = trainingPipelineResponse.getError(); + System.out.println("\tError"); + System.out.format("\t\tCode: %s\n", status.getCode()); + System.out.format("\t\tMessage: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_create_training_pipeline_video_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoObjectTrackingSample.java b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoObjectTrackingSample.java new file mode 100644 index 00000000000..3bd30b4b9d5 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/CreateTrainingPipelineVideoObjectTrackingSample.java @@ -0,0 +1,172 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_create_training_pipeline_video_object_tracking_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.cloud.aiplatform.v1.schema.trainingjob.definition.AutoMlVideoObjectTrackingInputs; +import com.google.cloud.aiplatform.v1.schema.trainingjob.definition.AutoMlVideoObjectTrackingInputs.ModelType; +import com.google.rpc.Status; +import java.io.IOException; + +public class CreateTrainingPipelineVideoObjectTrackingSample { + + public static void main(String[] args) throws IOException { + String trainingPipelineVideoObjectTracking = + "YOUR_TRAINING_PIPELINE_VIDEO_OBJECT_TRACKING_DISPLAY_NAME"; + String datasetId = "YOUR_DATASET_ID"; + String modelDisplayName = "YOUR_MODEL_DISPLAY_NAME"; + String project = "YOUR_PROJECT_ID"; + createTrainingPipelineVideoObjectTracking( + trainingPipelineVideoObjectTracking, datasetId, modelDisplayName, project); + } + + static void createTrainingPipelineVideoObjectTracking( + String trainingPipelineVideoObjectTracking, + String datasetId, + String modelDisplayName, + String project) + throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + String trainingTaskDefinition = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/" + + "automl_video_object_tracking_1.0.0.yaml"; + LocationName locationName = LocationName.of(project, location); + + AutoMlVideoObjectTrackingInputs trainingTaskInputs = + AutoMlVideoObjectTrackingInputs.newBuilder().setModelType(ModelType.CLOUD).build(); + + InputDataConfig inputDataConfig = + InputDataConfig.newBuilder().setDatasetId(datasetId).build(); + Model modelToUpload = Model.newBuilder().setDisplayName(modelDisplayName).build(); + TrainingPipeline trainingPipeline = + TrainingPipeline.newBuilder() + .setDisplayName(trainingPipelineVideoObjectTracking) + .setTrainingTaskDefinition(trainingTaskDefinition) + .setTrainingTaskInputs(ValueConverter.toValue(trainingTaskInputs)) + .setInputDataConfig(inputDataConfig) + .setModelToUpload(modelToUpload) + .build(); + + TrainingPipeline createTrainingPipelineResponse = + pipelineServiceClient.createTrainingPipeline(locationName, trainingPipeline); + + System.out.println("Create Training Pipeline Video Object Tracking Response"); + System.out.format("Name: %s\n", createTrainingPipelineResponse.getName()); + System.out.format("Display Name: %s\n", createTrainingPipelineResponse.getDisplayName()); + + System.out.format( + "Training Task Definition %s\n", + createTrainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "Training Task Inputs: %s\n", + createTrainingPipelineResponse.getTrainingTaskInputs().toString()); + System.out.format( + "Training Task Metadata: %s\n", + createTrainingPipelineResponse.getTrainingTaskMetadata().toString()); + + System.out.format("State: %s\n", createTrainingPipelineResponse.getState().toString()); + System.out.format( + "Create Time: %s\n", createTrainingPipelineResponse.getCreateTime().toString()); + System.out.format("StartTime %s\n", createTrainingPipelineResponse.getStartTime().toString()); + System.out.format("End Time: %s\n", createTrainingPipelineResponse.getEndTime().toString()); + System.out.format( + "Update Time: %s\n", createTrainingPipelineResponse.getUpdateTime().toString()); + System.out.format("Labels: %s\n", createTrainingPipelineResponse.getLabelsMap().toString()); + + InputDataConfig inputDataConfigResponse = createTrainingPipelineResponse.getInputDataConfig(); + System.out.println("Input Data config"); + System.out.format("Dataset Id: %s\n", inputDataConfigResponse.getDatasetId()); + System.out.format("Annotations Filter: %s\n", inputDataConfigResponse.getAnnotationsFilter()); + + FractionSplit fractionSplit = inputDataConfigResponse.getFractionSplit(); + System.out.println("Fraction split"); + System.out.format("Training Fraction: %s\n", fractionSplit.getTrainingFraction()); + System.out.format("Validation Fraction: %s\n", fractionSplit.getValidationFraction()); + System.out.format("Test Fraction: %s\n", fractionSplit.getTestFraction()); + + FilterSplit filterSplit = inputDataConfigResponse.getFilterSplit(); + System.out.println("Filter Split"); + System.out.format("Training Filter: %s\n", filterSplit.getTrainingFilter()); + System.out.format("Validation Filter: %s\n", filterSplit.getValidationFilter()); + System.out.format("Test Filter: %s\n", filterSplit.getTestFilter()); + + PredefinedSplit predefinedSplit = inputDataConfigResponse.getPredefinedSplit(); + System.out.println("Predefined Split"); + System.out.format("Key: %s\n", predefinedSplit.getKey()); + + TimestampSplit timestampSplit = inputDataConfigResponse.getTimestampSplit(); + System.out.println("Timestamp Split"); + System.out.format("Training Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("Validation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("Test Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("Key: %s\n", timestampSplit.getKey()); + + Model modelResponse = createTrainingPipelineResponse.getModelToUpload(); + System.out.println("Model To Upload"); + System.out.format("Name: %s\n", modelResponse.getName()); + System.out.format("Display Name: %s\n", modelResponse.getDisplayName()); + System.out.format("Description: %s\n", modelResponse.getDescription()); + System.out.format("Metadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("Metadata: %s\n", modelResponse.getMetadata()); + + System.out.format("Training Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("Artifact Uri: %s\n", modelResponse.getArtifactUri()); + + System.out.format( + "Supported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList().toString()); + System.out.format( + "Supported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList().toString()); + System.out.format( + "Supported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList().toString()); + + System.out.format("Create Time: %s\n", modelResponse.getCreateTime()); + System.out.format("Update Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("Labels: %s\n", modelResponse.getLabelsMap()); + + Status status = createTrainingPipelineResponse.getError(); + System.out.println("Error"); + System.out.format("Code: %s\n", status.getCode()); + System.out.format("Message: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_create_training_pipeline_video_object_tracking_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeleteBatchPredictionJobSample.java b/aiplatform/src/main/java/aiplatform/DeleteBatchPredictionJobSample.java new file mode 100644 index 00000000000..e0675190da6 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeleteBatchPredictionJobSample.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_delete_batch_prediction_job_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.BatchPredictionJobName; +import com.google.cloud.aiplatform.v1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeleteBatchPredictionJobSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String batchPredictionJobId = "YOUR_BATCH_PREDICTION_JOB_ID"; + deleteBatchPredictionJobSample(project, batchPredictionJobId); + } + + static void deleteBatchPredictionJobSample(String project, String batchPredictionJobId) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + JobServiceSettings jobServiceSettings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient jobServiceClient = JobServiceClient.create(jobServiceSettings)) { + String location = "us-central1"; + + BatchPredictionJobName batchPredictionJobName = + BatchPredictionJobName.of(project, location, batchPredictionJobId); + + OperationFuture operationFuture = + jobServiceClient.deleteBatchPredictionJobAsync(batchPredictionJobName); + System.out.format("Operation name: %s\n", operationFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + operationFuture.get(300, TimeUnit.SECONDS); + + System.out.println("Deleted Batch Prediction Job."); + } + } +} +// [END aiplatform_delete_batch_prediction_job_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeleteDataLabelingJobSample.java b/aiplatform/src/main/java/aiplatform/DeleteDataLabelingJobSample.java new file mode 100644 index 00000000000..b8c6b969b4a --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeleteDataLabelingJobSample.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_delete_data_labeling_job_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DataLabelingJobName; +import com.google.cloud.aiplatform.v1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeleteDataLabelingJobSample { + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String dataLabelingJobId = "YOUR_DATA_LABELING_JOB_ID"; + deleteDataLabelingJob(project, dataLabelingJobId); + } + + static void deleteDataLabelingJob(String project, String dataLabelingJobId) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + JobServiceSettings jobServiceSettings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient jobServiceClient = JobServiceClient.create(jobServiceSettings)) { + String location = "us-central1"; + + DataLabelingJobName dataLabelingJobName = + DataLabelingJobName.of(project, location, dataLabelingJobId); + + OperationFuture operationFuture = + jobServiceClient.deleteDataLabelingJobAsync(dataLabelingJobName); + System.out.format("Operation name: %s\n", operationFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + operationFuture.get(300, TimeUnit.SECONDS); + + System.out.format("Deleted Data Labeling Job."); + } + } +} +// [END aiplatform_delete_data_labeling_job_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeleteDatasetSample.java b/aiplatform/src/main/java/aiplatform/DeleteDatasetSample.java new file mode 100644 index 00000000000..30af542d339 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeleteDatasetSample.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_delete_dataset_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.DeleteOperationMetadata; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeleteDatasetSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + deleteDatasetSample(project, datasetId); + } + + static void deleteDatasetSample(String project, String datasetId) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + DatasetName datasetName = DatasetName.of(project, location, datasetId); + + OperationFuture operationFuture = + datasetServiceClient.deleteDatasetAsync(datasetName); + System.out.format("Operation name: %s\n", operationFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + operationFuture.get(300, TimeUnit.SECONDS); + + System.out.format("Deleted Dataset."); + } + } +} +// [END aiplatform_delete_dataset_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeleteEndpointSample.java b/aiplatform/src/main/java/aiplatform/DeleteEndpointSample.java new file mode 100644 index 00000000000..5767b588809 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeleteEndpointSample.java @@ -0,0 +1,67 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_delete_endpoint_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.EndpointServiceClient; +import com.google.cloud.aiplatform.v1.EndpointServiceSettings; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeleteEndpointSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String endpointId = "YOUR_ENDPOINT_ID"; + deleteEndpointSample(project, endpointId); + } + + static void deleteEndpointSample(String project, String endpointId) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + EndpointServiceSettings endpointServiceSettings = + EndpointServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (EndpointServiceClient endpointServiceClient = + EndpointServiceClient.create(endpointServiceSettings)) { + String location = "us-central1"; + EndpointName endpointName = EndpointName.of(project, location, endpointId); + + OperationFuture operationFuture = + endpointServiceClient.deleteEndpointAsync(endpointName); + System.out.format("Operation name: %s\n", operationFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Empty deleteResponse = operationFuture.get(300, TimeUnit.SECONDS); + + System.out.format("Delete Endpoint Response: %s\n", deleteResponse); + } + } +} +// [END aiplatform_delete_endpoint_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeleteEntityTypeSample.java b/aiplatform/src/main/java/aiplatform/DeleteEntityTypeSample.java new file mode 100644 index 00000000000..00e7c5e36af --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeleteEntityTypeSample.java @@ -0,0 +1,87 @@ +/* + * 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. + * + * + * Delete an entity type from featurestore resource. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_delete_entity_type_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DeleteEntityTypeRequest; +import com.google.cloud.aiplatform.v1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1.EntityTypeName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeleteEntityTypeSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 300; + deleteEntityTypeSample(project, featurestoreId, entityTypeId, location, endpoint, timeout); + } + + static void deleteEntityTypeSample( + String project, + String featurestoreId, + String entityTypeId, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + DeleteEntityTypeRequest deleteEntityTypeRequest = + DeleteEntityTypeRequest.newBuilder() + .setName( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .setForce(true) + .build(); + + OperationFuture operationFuture = + featurestoreServiceClient.deleteEntityTypeAsync(deleteEntityTypeRequest); + System.out.format("Operation name: %s%n", operationFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + operationFuture.get(timeout, TimeUnit.SECONDS); + + System.out.format("Deleted Entity Type."); + } + } +} +// [END aiplatform_delete_entity_type_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeleteExportModelSample.java b/aiplatform/src/main/java/aiplatform/DeleteExportModelSample.java new file mode 100644 index 00000000000..d6ed1995714 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeleteExportModelSample.java @@ -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. + */ + +package aiplatform; + +// [START aiplatform_delete_export_model_sample] + +import com.google.cloud.storage.Blob; +import com.google.cloud.storage.Storage; +import com.google.cloud.storage.StorageOptions; + +public class DeleteExportModelSample { + + public static void main(String[] args) { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String bucketName = "YOUR_BUCKET_NAME"; + String folderName = "YOUR_FOLDER_NAME"; + deleteExportModelSample(project, bucketName, folderName); + } + + static void deleteExportModelSample(String project, String bucketName, String folderName) { + Storage storage = StorageOptions.newBuilder().setProjectId(project).build().getService(); + Iterable blobs = + storage.list(bucketName, Storage.BlobListOption.prefix(folderName)).iterateAll(); + for (Blob blob : blobs) { + blob.delete(Blob.BlobSourceOption.generationMatch()); + } + System.out.println("Export Model Deleted"); + } +} +// [END aiplatform_delete_export_model_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeleteFeatureSample.java b/aiplatform/src/main/java/aiplatform/DeleteFeatureSample.java new file mode 100644 index 00000000000..bc77d5c804e --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeleteFeatureSample.java @@ -0,0 +1,90 @@ +/* + * 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. + * + * + * Delete a single feature from an existing entity type. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_delete_feature_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DeleteFeatureRequest; +import com.google.cloud.aiplatform.v1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1.FeatureName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeleteFeatureSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String featureId = "YOUR_FEATURE_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 300; + + deleteFeatureSample( + project, featurestoreId, entityTypeId, featureId, location, endpoint, timeout); + } + + static void deleteFeatureSample( + String project, + String featurestoreId, + String entityTypeId, + String featureId, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + DeleteFeatureRequest deleteFeatureRequest = + DeleteFeatureRequest.newBuilder() + .setName( + FeatureName.of(project, location, featurestoreId, entityTypeId, featureId) + .toString()) + .build(); + + OperationFuture operationFuture = + featurestoreServiceClient.deleteFeatureAsync(deleteFeatureRequest); + System.out.format("Operation name: %s%n", operationFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + operationFuture.get(timeout, TimeUnit.SECONDS); + System.out.format("Deleted Feature."); + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_delete_feature_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeleteFeaturestoreSample.java b/aiplatform/src/main/java/aiplatform/DeleteFeaturestoreSample.java new file mode 100644 index 00000000000..eb69ad35020 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeleteFeaturestoreSample.java @@ -0,0 +1,86 @@ +/* + * 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. + * + * + * Delete a featurestore. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_delete_featurestore_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DeleteFeaturestoreRequest; +import com.google.cloud.aiplatform.v1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1.FeaturestoreName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeleteFeaturestoreSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + boolean useForce = true; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 60; + deleteFeaturestoreSample(project, featurestoreId, useForce, location, endpoint, timeout); + } + + static void deleteFeaturestoreSample( + String project, + String featurestoreId, + boolean useForce, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + DeleteFeaturestoreRequest deleteFeaturestoreRequest = + DeleteFeaturestoreRequest.newBuilder() + .setName(FeaturestoreName.of(project, location, featurestoreId).toString()) + .setForce(useForce) + .build(); + + OperationFuture operationFuture = + featurestoreServiceClient.deleteFeaturestoreAsync(deleteFeaturestoreRequest); + System.out.format("Operation name: %s%n", operationFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + operationFuture.get(timeout, TimeUnit.SECONDS); + + System.out.format("Deleted Featurestore."); + } + } +} +// [END aiplatform_delete_featurestore_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeleteModelSample.java b/aiplatform/src/main/java/aiplatform/DeleteModelSample.java new file mode 100644 index 00000000000..f3ee72260c6 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeleteModelSample.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_delete_model_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeleteModelSample { + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + deleteModel(project, modelId); + } + + static void deleteModel(String project, String modelId) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelName modelName = ModelName.of(project, location, modelId); + OperationFuture operationFuture = + modelServiceClient.deleteModelAsync(modelName); + System.out.format("Operation name: %s\n", operationFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + operationFuture.get(300, TimeUnit.SECONDS); + System.out.format("Deleted Model."); + } + } +} +// [END aiplatform_delete_model_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeleteTrainingPipelineSample.java b/aiplatform/src/main/java/aiplatform/DeleteTrainingPipelineSample.java new file mode 100644 index 00000000000..e6256c6b633 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeleteTrainingPipelineSample.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_delete_training_pipeline_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.TrainingPipelineName; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeleteTrainingPipelineSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String trainingPipelineId = "YOUR_TRAINING_PIPELINE_ID"; + String project = "YOUR_PROJECT_ID"; + deleteTrainingPipelineSample(project, trainingPipelineId); + } + + static void deleteTrainingPipelineSample(String project, String trainingPipelineId) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + TrainingPipelineName trainingPipelineName = + TrainingPipelineName.of(project, location, trainingPipelineId); + + OperationFuture operationFuture = + pipelineServiceClient.deleteTrainingPipelineAsync(trainingPipelineName); + System.out.format("Operation name: %s\n", operationFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + operationFuture.get(300, TimeUnit.SECONDS); + + System.out.format("Deleted Training Pipeline."); + } + } +} +// [END aiplatform_delete_training_pipeline_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeployModelCustomTrainedModelSample.java b/aiplatform/src/main/java/aiplatform/DeployModelCustomTrainedModelSample.java new file mode 100644 index 00000000000..2548637635e --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeployModelCustomTrainedModelSample.java @@ -0,0 +1,92 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_deploy_model_custom_trained_model_sample] +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DedicatedResources; +import com.google.cloud.aiplatform.v1.DeployModelOperationMetadata; +import com.google.cloud.aiplatform.v1.DeployModelResponse; +import com.google.cloud.aiplatform.v1.DeployedModel; +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.EndpointServiceClient; +import com.google.cloud.aiplatform.v1.EndpointServiceSettings; +import com.google.cloud.aiplatform.v1.MachineSpec; +import com.google.cloud.aiplatform.v1.ModelName; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; + +public class DeployModelCustomTrainedModelSample { + + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String endpointId = "ENDPOINT_ID"; + String modelName = "MODEL_NAME"; + String deployedModelDisplayName = "DEPLOYED_MODEL_DISPLAY_NAME"; + deployModelCustomTrainedModelSample(project, endpointId, modelName, deployedModelDisplayName); + } + + static void deployModelCustomTrainedModelSample( + String project, String endpointId, String model, String deployedModelDisplayName) + throws IOException, ExecutionException, InterruptedException { + EndpointServiceSettings settings = + EndpointServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (EndpointServiceClient client = EndpointServiceClient.create(settings)) { + MachineSpec machineSpec = MachineSpec.newBuilder().setMachineType("n1-standard-2").build(); + DedicatedResources dedicatedResources = + DedicatedResources.newBuilder().setMinReplicaCount(1).setMachineSpec(machineSpec).build(); + + String modelName = ModelName.of(project, location, model).toString(); + DeployedModel deployedModel = + DeployedModel.newBuilder() + .setModel(modelName) + .setDisplayName(deployedModelDisplayName) + // `dedicated_resources` must be used for non-AutoML models + .setDedicatedResources(dedicatedResources) + .build(); + // key '0' assigns traffic for the newly deployed model + // Traffic percentage values must add up to 100 + // Leave dictionary empty if endpoint should not accept any traffic + Map trafficSplit = new HashMap<>(); + trafficSplit.put("0", 100); + EndpointName endpoint = EndpointName.of(project, location, endpointId); + OperationFuture response = + client.deployModelAsync(endpoint, deployedModel, trafficSplit); + + // You can use OperationFuture.getInitialFuture to get a future representing the initial + // response to the request, which contains information while the operation is in progress. + System.out.format("Operation name: %s\n", response.getInitialFuture().get().getName()); + + // OperationFuture.get() will block until the operation is finished. + DeployModelResponse deployModelResponse = response.get(); + System.out.format("deployModelResponse: %s\n", deployModelResponse); + } + } +} + +// [END aiplatform_deploy_model_custom_trained_model_sample] diff --git a/aiplatform/src/main/java/aiplatform/DeployModelSample.java b/aiplatform/src/main/java/aiplatform/DeployModelSample.java new file mode 100644 index 00000000000..f950afd9656 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/DeployModelSample.java @@ -0,0 +1,113 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_deploy_model_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.AutomaticResources; +import com.google.cloud.aiplatform.v1.DedicatedResources; +import com.google.cloud.aiplatform.v1.DeployModelOperationMetadata; +import com.google.cloud.aiplatform.v1.DeployModelResponse; +import com.google.cloud.aiplatform.v1.DeployedModel; +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.EndpointServiceClient; +import com.google.cloud.aiplatform.v1.EndpointServiceSettings; +import com.google.cloud.aiplatform.v1.MachineSpec; +import com.google.cloud.aiplatform.v1.ModelName; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class DeployModelSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String deployedModelDisplayName = "YOUR_DEPLOYED_MODEL_DISPLAY_NAME"; + String endpointId = "YOUR_ENDPOINT_NAME"; + String modelId = "YOUR_MODEL_ID"; + deployModelSample(project, deployedModelDisplayName, endpointId, modelId); + } + + static void deployModelSample( + String project, String deployedModelDisplayName, String endpointId, String modelId) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + EndpointServiceSettings endpointServiceSettings = + EndpointServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (EndpointServiceClient endpointServiceClient = + EndpointServiceClient.create(endpointServiceSettings)) { + String location = "us-central1"; + EndpointName endpointName = EndpointName.of(project, location, endpointId); + // key '0' assigns traffic for the newly deployed model + // Traffic percentage values must add up to 100 + // Leave dictionary empty if endpoint should not accept any traffic + Map trafficSplit = new HashMap<>(); + trafficSplit.put("0", 100); + ModelName modelName = ModelName.of(project, location, modelId); + AutomaticResources automaticResourcesInput = + AutomaticResources.newBuilder().setMinReplicaCount(1).setMaxReplicaCount(1).build(); + DeployedModel deployedModelInput = + DeployedModel.newBuilder() + .setModel(modelName.toString()) + .setDisplayName(deployedModelDisplayName) + .setAutomaticResources(automaticResourcesInput) + .build(); + + OperationFuture deployModelResponseFuture = + endpointServiceClient.deployModelAsync(endpointName, deployedModelInput, trafficSplit); + System.out.format( + "Operation name: %s\n", deployModelResponseFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + DeployModelResponse deployModelResponse = deployModelResponseFuture.get(20, TimeUnit.MINUTES); + + System.out.println("Deploy Model Response"); + DeployedModel deployedModel = deployModelResponse.getDeployedModel(); + System.out.println("\tDeployed Model"); + System.out.format("\t\tid: %s\n", deployedModel.getId()); + System.out.format("\t\tmodel: %s\n", deployedModel.getModel()); + System.out.format("\t\tDisplay Name: %s\n", deployedModel.getDisplayName()); + System.out.format("\t\tCreate Time: %s\n", deployedModel.getCreateTime()); + + DedicatedResources dedicatedResources = deployedModel.getDedicatedResources(); + System.out.println("\t\tDedicated Resources"); + System.out.format("\t\t\tMin Replica Count: %s\n", dedicatedResources.getMinReplicaCount()); + + MachineSpec machineSpec = dedicatedResources.getMachineSpec(); + System.out.println("\t\t\tMachine Spec"); + System.out.format("\t\t\t\tMachine Type: %s\n", machineSpec.getMachineType()); + System.out.format("\t\t\t\tAccelerator Type: %s\n", machineSpec.getAcceleratorType()); + System.out.format("\t\t\t\tAccelerator Count: %s\n", machineSpec.getAcceleratorCount()); + + AutomaticResources automaticResources = deployedModel.getAutomaticResources(); + System.out.println("\t\tAutomatic Resources"); + System.out.format("\t\t\tMin Replica Count: %s\n", automaticResources.getMinReplicaCount()); + System.out.format("\t\t\tMax Replica Count: %s\n", automaticResources.getMaxReplicaCount()); + } + } +} +// [END aiplatform_deploy_model_sample] diff --git a/aiplatform/src/main/java/aiplatform/ExportFeatureValuesSample.java b/aiplatform/src/main/java/aiplatform/ExportFeatureValuesSample.java new file mode 100644 index 00000000000..6bb7b00d66e --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ExportFeatureValuesSample.java @@ -0,0 +1,119 @@ +/* + * 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. + * + * + * Bulk export feature values from a featurestore. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_export_feature_values_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.BigQueryDestination; +import com.google.cloud.aiplatform.v1.EntityTypeName; +import com.google.cloud.aiplatform.v1.ExportFeatureValuesOperationMetadata; +import com.google.cloud.aiplatform.v1.ExportFeatureValuesRequest; +import com.google.cloud.aiplatform.v1.ExportFeatureValuesRequest.FullExport; +import com.google.cloud.aiplatform.v1.ExportFeatureValuesResponse; +import com.google.cloud.aiplatform.v1.FeatureSelector; +import com.google.cloud.aiplatform.v1.FeatureValueDestination; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.IdMatcher; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ExportFeatureValuesSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String destinationTableUri = "YOUR_DESTINATION_TABLE_URI"; + List featureSelectorIds = Arrays.asList("title", "genres", "average_rating"); + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 300; + exportFeatureValuesSample( + project, + featurestoreId, + entityTypeId, + destinationTableUri, + featureSelectorIds, + location, + endpoint, + timeout); + } + + static void exportFeatureValuesSample( + String project, + String featurestoreId, + String entityTypeId, + String destinationTableUri, + List featureSelectorIds, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + FeatureSelector featureSelector = + FeatureSelector.newBuilder() + .setIdMatcher(IdMatcher.newBuilder().addAllIds(featureSelectorIds).build()) + .build(); + + ExportFeatureValuesRequest exportFeatureValuesRequest = + ExportFeatureValuesRequest.newBuilder() + .setEntityType( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .setDestination( + FeatureValueDestination.newBuilder() + .setBigqueryDestination( + BigQueryDestination.newBuilder().setOutputUri(destinationTableUri))) + .setFeatureSelector(featureSelector) + .setFullExport(FullExport.newBuilder()) + .build(); + + OperationFuture + exportFeatureValuesFuture = + featurestoreServiceClient.exportFeatureValuesAsync(exportFeatureValuesRequest); + System.out.format( + "Operation name: %s%n", exportFeatureValuesFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + ExportFeatureValuesResponse exportFeatureValuesResponse = + exportFeatureValuesFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Export Feature Values Response"); + System.out.println(exportFeatureValuesResponse); + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_export_feature_values_sample] diff --git a/aiplatform/src/main/java/aiplatform/ExportFeatureValuesSnapshotSample.java b/aiplatform/src/main/java/aiplatform/ExportFeatureValuesSnapshotSample.java new file mode 100644 index 00000000000..6d48d34d06c --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ExportFeatureValuesSnapshotSample.java @@ -0,0 +1,119 @@ +/* + * 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. + * + * + * Bulk export feature values from a featurestore. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_export_feature_values_snapshot_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.BigQueryDestination; +import com.google.cloud.aiplatform.v1.EntityTypeName; +import com.google.cloud.aiplatform.v1.ExportFeatureValuesOperationMetadata; +import com.google.cloud.aiplatform.v1.ExportFeatureValuesRequest; +import com.google.cloud.aiplatform.v1.ExportFeatureValuesRequest.SnapshotExport; +import com.google.cloud.aiplatform.v1.ExportFeatureValuesResponse; +import com.google.cloud.aiplatform.v1.FeatureSelector; +import com.google.cloud.aiplatform.v1.FeatureValueDestination; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.IdMatcher; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ExportFeatureValuesSnapshotSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String destinationTableUri = "YOUR_DESTINATION_TABLE_URI"; + List featureSelectorIds = Arrays.asList("title", "genres", "average_rating"); + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 300; + exportFeatureValuesSnapshotSample( + project, + featurestoreId, + entityTypeId, + destinationTableUri, + featureSelectorIds, + location, + endpoint, + timeout); + } + + static void exportFeatureValuesSnapshotSample( + String project, + String featurestoreId, + String entityTypeId, + String destinationTableUri, + List featureSelectorIds, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + FeatureSelector featureSelector = + FeatureSelector.newBuilder() + .setIdMatcher(IdMatcher.newBuilder().addAllIds(featureSelectorIds).build()) + .build(); + + ExportFeatureValuesRequest exportFeatureValuesRequest = + ExportFeatureValuesRequest.newBuilder() + .setEntityType( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .setDestination( + FeatureValueDestination.newBuilder() + .setBigqueryDestination( + BigQueryDestination.newBuilder().setOutputUri(destinationTableUri))) + .setFeatureSelector(featureSelector) + .setSnapshotExport(SnapshotExport.newBuilder()) + .build(); + + OperationFuture + exportFeatureValuesFuture = + featurestoreServiceClient.exportFeatureValuesAsync(exportFeatureValuesRequest); + System.out.format( + "Operation name: %s%n", exportFeatureValuesFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + ExportFeatureValuesResponse exportFeatureValuesResponse = + exportFeatureValuesFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Snapshot Export Feature Values Response"); + System.out.println(exportFeatureValuesResponse); + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_export_feature_values_snapshot_sample] diff --git a/aiplatform/src/main/java/aiplatform/ExportModelSample.java b/aiplatform/src/main/java/aiplatform/ExportModelSample.java new file mode 100644 index 00000000000..1979c7ce116 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ExportModelSample.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_export_model_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.ExportModelOperationMetadata; +import com.google.cloud.aiplatform.v1.ExportModelRequest; +import com.google.cloud.aiplatform.v1.ExportModelResponse; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ExportModelSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String gcsDestinationOutputUriPrefix = "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_destination/"; + String exportFormat = "YOUR_EXPORT_FORMAT"; + exportModelSample(project, modelId, gcsDestinationOutputUriPrefix, exportFormat); + } + + static void exportModelSample( + String project, String modelId, String gcsDestinationOutputUriPrefix, String exportFormat) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + GcsDestination.Builder gcsDestination = GcsDestination.newBuilder(); + gcsDestination.setOutputUriPrefix(gcsDestinationOutputUriPrefix); + + ModelName modelName = ModelName.of(project, location, modelId); + ExportModelRequest.OutputConfig outputConfig = + ExportModelRequest.OutputConfig.newBuilder() + .setExportFormatId(exportFormat) + .setArtifactDestination(gcsDestination) + .build(); + + OperationFuture exportModelResponseFuture = + modelServiceClient.exportModelAsync(modelName, outputConfig); + System.out.format( + "Operation name: %s\n", exportModelResponseFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + ExportModelResponse exportModelResponse = + exportModelResponseFuture.get(300, TimeUnit.SECONDS); + + System.out.format("Export Model Response: %s\n", exportModelResponse); + } + } +} +// [END aiplatform_export_model_sample] diff --git a/aiplatform/src/main/java/aiplatform/ExportModelTabularClassificationSample.java b/aiplatform/src/main/java/aiplatform/ExportModelTabularClassificationSample.java new file mode 100644 index 00000000000..9a722790eb6 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ExportModelTabularClassificationSample.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_export_model_tabular_classification_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.ExportModelOperationMetadata; +import com.google.cloud.aiplatform.v1.ExportModelRequest; +import com.google.cloud.aiplatform.v1.ExportModelResponse; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ExportModelTabularClassificationSample { + public static void main(String[] args) + throws InterruptedException, ExecutionException, TimeoutException, IOException { + // TODO(developer): Replace these variables before running the sample. + String gcsDestinationOutputUriPrefix = "gs://your-gcs-bucket/destination_path"; + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + exportModelTableClassification(gcsDestinationOutputUriPrefix, project, modelId); + } + + static void exportModelTableClassification( + String gcsDestinationOutputUriPrefix, String project, String modelId) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelName modelName = ModelName.of(project, location, modelId); + + GcsDestination.Builder gcsDestination = GcsDestination.newBuilder(); + gcsDestination.setOutputUriPrefix(gcsDestinationOutputUriPrefix); + ExportModelRequest.OutputConfig outputConfig = + ExportModelRequest.OutputConfig.newBuilder() + .setExportFormatId("tf-saved-model") + .setArtifactDestination(gcsDestination) + .build(); + + OperationFuture exportModelResponseFuture = + modelServiceClient.exportModelAsync(modelName, outputConfig); + System.out.format( + "Operation name: %s\n", exportModelResponseFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + ExportModelResponse exportModelResponse = + exportModelResponseFuture.get(300, TimeUnit.SECONDS); + System.out.format( + "Export Model Tabular Classification Response: %s", exportModelResponse.toString()); + } + } +} +// [END aiplatform_export_model_tabular_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/ExportModelVideoActionRecognitionSample.java b/aiplatform/src/main/java/aiplatform/ExportModelVideoActionRecognitionSample.java new file mode 100644 index 00000000000..54e590085cb --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ExportModelVideoActionRecognitionSample.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_export_model_video_action_recognition_sample] +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.ExportModelOperationMetadata; +import com.google.cloud.aiplatform.v1.ExportModelRequest; +import com.google.cloud.aiplatform.v1.ExportModelResponse; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +public class ExportModelVideoActionRecognitionSample { + + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String modelId = "MODEL_ID"; + String gcsDestinationOutputUriPrefix = "GCS_DESTINATION_OUTPUT_URI_PREFIX"; + String exportFormat = "EXPORT_FORMAT"; + exportModelVideoActionRecognitionSample( + project, modelId, gcsDestinationOutputUriPrefix, exportFormat); + } + + static void exportModelVideoActionRecognitionSample( + String project, String modelId, String gcsDestinationOutputUriPrefix, String exportFormat) + throws IOException, ExecutionException, InterruptedException { + ModelServiceSettings settings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient client = ModelServiceClient.create(settings)) { + GcsDestination gcsDestination = + GcsDestination.newBuilder().setOutputUriPrefix(gcsDestinationOutputUriPrefix).build(); + ExportModelRequest.OutputConfig outputConfig = + ExportModelRequest.OutputConfig.newBuilder() + .setArtifactDestination(gcsDestination) + .setExportFormatId(exportFormat) + .build(); + ModelName name = ModelName.of(project, location, modelId); + OperationFuture response = + client.exportModelAsync(name, outputConfig); + + // You can use OperationFuture.getInitialFuture to get a future representing the initial + // response to the request, which contains information while the operation is in progress. + System.out.format("Operation name: %s\n", response.getInitialFuture().get().getName()); + + // OperationFuture.get() will block until the operation is finished. + ExportModelResponse exportModelResponse = response.get(); + System.out.format("exportModelResponse: %s\n", exportModelResponse); + } + } +} + +// [END aiplatform_export_model_video_action_recognition_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetBatchPredictionJobSample.java b/aiplatform/src/main/java/aiplatform/GetBatchPredictionJobSample.java new file mode 100644 index 00000000000..4e4ba6b3ebe --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetBatchPredictionJobSample.java @@ -0,0 +1,135 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_batch_prediction_job_sample] + +import com.google.cloud.aiplatform.v1.BatchPredictionJob; +import com.google.cloud.aiplatform.v1.BatchPredictionJob.InputConfig; +import com.google.cloud.aiplatform.v1.BatchPredictionJob.OutputConfig; +import com.google.cloud.aiplatform.v1.BatchPredictionJob.OutputInfo; +import com.google.cloud.aiplatform.v1.BatchPredictionJobName; +import com.google.cloud.aiplatform.v1.BigQueryDestination; +import com.google.cloud.aiplatform.v1.BigQuerySource; +import com.google.cloud.aiplatform.v1.CompletionStats; +import com.google.cloud.aiplatform.v1.GcsDestination; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import com.google.cloud.aiplatform.v1.ResourcesConsumed; +import com.google.protobuf.Any; +import com.google.rpc.Status; +import java.io.IOException; +import java.util.List; + +public class GetBatchPredictionJobSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String batchPredictionJobId = "YOUR_BATCH_PREDICTION_JOB_ID"; + getBatchPredictionJobSample(project, batchPredictionJobId); + } + + static void getBatchPredictionJobSample(String project, String batchPredictionJobId) + throws IOException { + JobServiceSettings jobServiceSettings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient jobServiceClient = JobServiceClient.create(jobServiceSettings)) { + String location = "us-central1"; + BatchPredictionJobName batchPredictionJobName = + BatchPredictionJobName.of(project, location, batchPredictionJobId); + + BatchPredictionJob batchPredictionJob = + jobServiceClient.getBatchPredictionJob(batchPredictionJobName); + + System.out.println("Get Batch Prediction Job Response"); + System.out.format("\tName: %s\n", batchPredictionJob.getName()); + System.out.format("\tDisplay Name: %s\n", batchPredictionJob.getDisplayName()); + System.out.format("\tModel: %s\n", batchPredictionJob.getModel()); + + System.out.format("\tModel Parameters: %s\n", batchPredictionJob.getModelParameters()); + System.out.format("\tState: %s\n", batchPredictionJob.getState()); + + System.out.format("\tCreate Time: %s\n", batchPredictionJob.getCreateTime()); + System.out.format("\tStart Time: %s\n", batchPredictionJob.getStartTime()); + System.out.format("\tEnd Time: %s\n", batchPredictionJob.getEndTime()); + System.out.format("\tUpdate Time: %s\n", batchPredictionJob.getUpdateTime()); + System.out.format("\tLabels: %s\n", batchPredictionJob.getLabelsMap()); + + InputConfig inputConfig = batchPredictionJob.getInputConfig(); + System.out.println("\tInput Config"); + System.out.format("\t\tInstances Format: %s\n", inputConfig.getInstancesFormat()); + + GcsSource gcsSource = inputConfig.getGcsSource(); + System.out.println("\t\tGcs Source"); + System.out.format("\t\t\tUris: %s\n", gcsSource.getUrisList()); + + BigQuerySource bigquerySource = inputConfig.getBigquerySource(); + System.out.println("\t\tBigquery Source"); + System.out.format("\t\t\tInput Uri: %s\n", bigquerySource.getInputUri()); + + OutputConfig outputConfig = batchPredictionJob.getOutputConfig(); + System.out.println("\tOutput Config"); + System.out.format("\t\tPredictions Format: %s\n", outputConfig.getPredictionsFormat()); + + GcsDestination gcsDestination = outputConfig.getGcsDestination(); + System.out.println("\t\tGcs Destination"); + System.out.format("\t\t\tOutput Uri Prefix: %s\n", gcsDestination.getOutputUriPrefix()); + + BigQueryDestination bigqueryDestination = outputConfig.getBigqueryDestination(); + System.out.println("\t\tBigquery Destination"); + System.out.format("\t\t\tOutput Uri: %s\n", bigqueryDestination.getOutputUri()); + + OutputInfo outputInfo = batchPredictionJob.getOutputInfo(); + System.out.println("\tOutput Info"); + System.out.format("\t\tGcs Output Directory: %s\n", outputInfo.getGcsOutputDirectory()); + System.out.format("\t\tBigquery Output Dataset: %s\n", outputInfo.getBigqueryOutputDataset()); + + Status status = batchPredictionJob.getError(); + System.out.println("\tError"); + System.out.format("\t\tCode: %s\n", status.getCode()); + System.out.format("\t\tMessage: %s\n", status.getMessage()); + + List detailsList = status.getDetailsList(); + + for (Status partialFailure : batchPredictionJob.getPartialFailuresList()) { + System.out.println("\tPartial Failure"); + System.out.format("\t\tCode: %s\n", partialFailure.getCode()); + System.out.format("\t\tMessage: %s\n", partialFailure.getMessage()); + List details = partialFailure.getDetailsList(); + } + + ResourcesConsumed resourcesConsumed = batchPredictionJob.getResourcesConsumed(); + System.out.println("\tResources Consumed"); + System.out.format("\t\tReplica Hours: %s\n", resourcesConsumed.getReplicaHours()); + + CompletionStats completionStats = batchPredictionJob.getCompletionStats(); + System.out.println("\tCompletion Stats"); + System.out.format("\t\tSuccessful Count: %s\n", completionStats.getSuccessfulCount()); + System.out.format("\t\tFailed Count: %s\n", completionStats.getFailedCount()); + System.out.format("\t\tIncomplete Count: %s\n", completionStats.getIncompleteCount()); + } + } +} +// [END aiplatform_get_batch_prediction_job_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetEntityTypeSample.java b/aiplatform/src/main/java/aiplatform/GetEntityTypeSample.java new file mode 100644 index 00000000000..f9e83f223ba --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetEntityTypeSample.java @@ -0,0 +1,70 @@ +/* + * 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. + * + * + * Get entity type details. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_get_entity_type_sample] + +import com.google.cloud.aiplatform.v1.EntityType; +import com.google.cloud.aiplatform.v1.EntityTypeName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.GetEntityTypeRequest; +import java.io.IOException; + +public class GetEntityTypeSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + getEntityTypeSample(project, featurestoreId, entityTypeId, location, endpoint); + } + + static void getEntityTypeSample( + String project, String featurestoreId, String entityTypeId, String location, String endpoint) + throws IOException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + GetEntityTypeRequest getEntityTypeRequest = + GetEntityTypeRequest.newBuilder() + .setName( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .build(); + + EntityType entityType = featurestoreServiceClient.getEntityType(getEntityTypeRequest); + System.out.println("Get Entity Type Response"); + System.out.println(entityType); + } + } +} +// [END aiplatform_get_entity_type_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetFeatureSample.java b/aiplatform/src/main/java/aiplatform/GetFeatureSample.java new file mode 100644 index 00000000000..f7e38adf1a9 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetFeatureSample.java @@ -0,0 +1,79 @@ +/* + * 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. + * + * + * Get feature details. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_get_feature_sample] + +import com.google.cloud.aiplatform.v1.Feature; +import com.google.cloud.aiplatform.v1.FeatureName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.GetFeatureRequest; +import java.io.IOException; + +public class GetFeatureSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String featureId = "YOUR_FEATURE_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + + getFeatureSample(project, featurestoreId, entityTypeId, featureId, location, endpoint); + } + + static void getFeatureSample( + String project, + String featurestoreId, + String entityTypeId, + String featureId, + String location, + String endpoint) + throws IOException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + GetFeatureRequest getFeatureRequest = + GetFeatureRequest.newBuilder() + .setName( + FeatureName.of(project, location, featurestoreId, entityTypeId, featureId) + .toString()) + .build(); + + Feature feature = featurestoreServiceClient.getFeature(getFeatureRequest); + System.out.println("Get Feature Response"); + System.out.println(feature); + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_get_feature_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetFeaturestoreSample.java b/aiplatform/src/main/java/aiplatform/GetFeaturestoreSample.java new file mode 100644 index 00000000000..1d8c4c77c98 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetFeaturestoreSample.java @@ -0,0 +1,67 @@ +/* + * 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. + * + * + * Gets details of a single featurestore. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_get_featurestore_sample] + +import com.google.cloud.aiplatform.v1beta1.Featurestore; +import com.google.cloud.aiplatform.v1beta1.FeaturestoreName; +import com.google.cloud.aiplatform.v1beta1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1beta1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1beta1.GetFeaturestoreRequest; +import java.io.IOException; + +public class GetFeaturestoreSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + getFeaturestoreSample(project, featurestoreId, location, endpoint); + } + + static void getFeaturestoreSample( + String project, String featurestoreId, String location, String endpoint) throws IOException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + GetFeaturestoreRequest getFeaturestoreRequest = + GetFeaturestoreRequest.newBuilder() + .setName(FeaturestoreName.of(project, location, featurestoreId).toString()) + .build(); + + Featurestore featurestore = featurestoreServiceClient.getFeaturestore(getFeaturestoreRequest); + System.out.println("Get Featurestore Response"); + System.out.println(featurestore); + } + } +} +// [END aiplatform_get_featurestore_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetHyperparameterTuningJobSample.java b/aiplatform/src/main/java/aiplatform/GetHyperparameterTuningJobSample.java new file mode 100644 index 00000000000..f886bc3325b --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetHyperparameterTuningJobSample.java @@ -0,0 +1,55 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_hyperparameter_tuning_job_sample] +import com.google.cloud.aiplatform.v1.HyperparameterTuningJob; +import com.google.cloud.aiplatform.v1.HyperparameterTuningJobName; +import com.google.cloud.aiplatform.v1.JobServiceClient; +import com.google.cloud.aiplatform.v1.JobServiceSettings; +import java.io.IOException; + +public class GetHyperparameterTuningJobSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String hyperparameterTuningJobId = "HYPERPARAMETER_TUNING_JOB_ID"; + getHyperparameterTuningJobSample(project, hyperparameterTuningJobId); + } + + static void getHyperparameterTuningJobSample(String project, String hyperparameterTuningJobId) + throws IOException { + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (JobServiceClient client = JobServiceClient.create(settings)) { + HyperparameterTuningJobName name = + HyperparameterTuningJobName.of(project, location, hyperparameterTuningJobId); + HyperparameterTuningJob response = client.getHyperparameterTuningJob(name); + System.out.format("response: %s\n", response); + } + } +} + +// [END aiplatform_get_hyperparameter_tuning_job_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationImageClassificationSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationImageClassificationSample.java new file mode 100644 index 00000000000..abcc2ec9f58 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationImageClassificationSample.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_image_classification_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationImageClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + getModelEvaluationImageClassificationSample(project, modelId, evaluationId); + } + + static void getModelEvaluationImageClassificationSample( + String project, String modelId, String evaluationId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + + ModelEvaluation modelEvaluation = modelServiceClient.getModelEvaluation(modelEvaluationName); + + System.out.println("Get Model Evaluation Image Classification Response"); + System.out.format("Model Name: %s\n", modelEvaluation.getName()); + System.out.format("Metrics Schema Uri: %s\n", modelEvaluation.getMetricsSchemaUri()); + System.out.format("Metrics: %s\n", modelEvaluation.getMetrics()); + System.out.format("Create Time: %s\n", modelEvaluation.getCreateTime()); + System.out.format("Slice Dimensions: %s\n", modelEvaluation.getSliceDimensionsList()); + } + } +} +// [END aiplatform_get_model_evaluation_image_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationImageObjectDetectionSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationImageObjectDetectionSample.java new file mode 100644 index 00000000000..fc85324116f --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationImageObjectDetectionSample.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_image_object_detection_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationImageObjectDetectionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + getModelEvaluationImageObjectDetectionSample(project, modelId, evaluationId); + } + + static void getModelEvaluationImageObjectDetectionSample( + String project, String modelId, String evaluationId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + + ModelEvaluation modelEvaluation = modelServiceClient.getModelEvaluation(modelEvaluationName); + + System.out.println("Get Model Evaluation Image Object Detection Response"); + System.out.format("\tName: %s\n", modelEvaluation.getName()); + System.out.format("\tMetrics Schema Uri: %s\n", modelEvaluation.getMetricsSchemaUri()); + System.out.format("\tMetrics: %s\n", modelEvaluation.getMetrics()); + System.out.format("\tCreate Time: %s\n", modelEvaluation.getCreateTime()); + System.out.format("\tSlice Dimensions: %s\n", modelEvaluation.getSliceDimensionsList()); + } + } +} +// [END aiplatform_get_model_evaluation_image_object_detection_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationSample.java new file mode 100644 index 00000000000..4944dda1c1d --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationSample.java @@ -0,0 +1,63 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + getModelEvaluationSample(project, modelId, evaluationId); + } + + static void getModelEvaluationSample(String project, String modelId, String evaluationId) + throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + + ModelEvaluation modelEvaluation = modelServiceClient.getModelEvaluation(modelEvaluationName); + + System.out.println("Get Model Evaluation Response"); + System.out.format("Model Name: %s\n", modelEvaluation.getName()); + System.out.format("Metrics Schema Uri: %s\n", modelEvaluation.getMetricsSchemaUri()); + System.out.format("Metrics: %s\n", modelEvaluation.getMetrics()); + System.out.format("Create Time: %s\n", modelEvaluation.getCreateTime()); + System.out.format("Slice Dimensions: %s\n", modelEvaluation.getSliceDimensionsList()); + } + } +} +// [END aiplatform_get_model_evaluation_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationSliceSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationSliceSample.java new file mode 100644 index 00000000000..1de771c185f --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationSliceSample.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_slice_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluationSlice; +import com.google.cloud.aiplatform.v1.ModelEvaluationSlice.Slice; +import com.google.cloud.aiplatform.v1.ModelEvaluationSliceName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationSliceSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + String sliceId = "YOUR_SLICE_ID"; + getModelEvaluationSliceSample(project, modelId, evaluationId, sliceId); + } + + static void getModelEvaluationSliceSample( + String project, String modelId, String evaluationId, String sliceId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelEvaluationSliceName modelEvaluationSliceName = + ModelEvaluationSliceName.of(project, location, modelId, evaluationId, sliceId); + + ModelEvaluationSlice modelEvaluationSlice = + modelServiceClient.getModelEvaluationSlice(modelEvaluationSliceName); + + System.out.println("Get Model Evaluation Slice Response"); + System.out.format("Model Evaluation Slice Name: %s\n", modelEvaluationSlice.getName()); + System.out.format("Metrics Schema Uri: %s\n", modelEvaluationSlice.getMetricsSchemaUri()); + System.out.format("Metrics: %s\n", modelEvaluationSlice.getMetrics()); + System.out.format("Create Time: %s\n", modelEvaluationSlice.getCreateTime()); + + Slice slice = modelEvaluationSlice.getSlice(); + System.out.format("Slice Dimensions: %s\n", slice.getDimension()); + System.out.format("Slice Value: %s\n", slice.getValue()); + } + } +} +// [END aiplatform_get_model_evaluation_slice_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationTabularClassificationSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationTabularClassificationSample.java new file mode 100644 index 00000000000..dc38eaede76 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationTabularClassificationSample.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_tabular_classification_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationTabularClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + getModelEvaluationTabularClassification(project, modelId, evaluationId); + } + + static void getModelEvaluationTabularClassification( + String project, String modelId, String evaluationId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + ModelEvaluation modelEvaluation = modelServiceClient.getModelEvaluation(modelEvaluationName); + + System.out.println("Get Model Evaluation Tabular Classification Response"); + System.out.format("\tName: %s\n", modelEvaluation.getName()); + System.out.format("\tMetrics Schema Uri: %s\n", modelEvaluation.getMetricsSchemaUri()); + System.out.format("\tMetrics: %s\n", modelEvaluation.getMetrics()); + System.out.format("\tCreate Time: %s\n", modelEvaluation.getCreateTime()); + System.out.format("\tSlice Dimensions: %s\n", modelEvaluation.getSliceDimensionsList()); + } + } +} +// [END aiplatform_get_model_evaluation_tabular_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationTabularRegressionSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationTabularRegressionSample.java new file mode 100644 index 00000000000..908f9a47859 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationTabularRegressionSample.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_tabular_regression_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationTabularRegressionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + getModelEvaluationTabularRegression(project, modelId, evaluationId); + } + + static void getModelEvaluationTabularRegression( + String project, String modelId, String evaluationId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + ModelEvaluation modelEvaluation = modelServiceClient.getModelEvaluation(modelEvaluationName); + + System.out.println("Get Model Evaluation Tabular Regression Response"); + System.out.format("\tName: %s\n", modelEvaluation.getName()); + System.out.format("\tMetrics Schema Uri: %s\n", modelEvaluation.getMetricsSchemaUri()); + System.out.format("\tMetrics: %s\n", modelEvaluation.getMetrics()); + System.out.format("\tCreate Time: %s\n", modelEvaluation.getCreateTime()); + System.out.format("\tSlice Dimensions: %s\n", modelEvaluation.getSliceDimensionsList()); + } + } +} +// [END aiplatform_get_model_evaluation_tabular_regression_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationTextClassificationSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationTextClassificationSample.java new file mode 100644 index 00000000000..912f4c6766b --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationTextClassificationSample.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_text_classification_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationTextClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + + getModelEvaluationTextClassificationSample(project, modelId, evaluationId); + } + + static void getModelEvaluationTextClassificationSample( + String project, String modelId, String evaluationId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + ModelEvaluation modelEvaluation = modelServiceClient.getModelEvaluation(modelEvaluationName); + + System.out.println("Get Model Evaluation Text Classification Response"); + System.out.format("\tModel Name: %s\n", modelEvaluation.getName()); + System.out.format("\tMetrics Schema Uri: %s\n", modelEvaluation.getMetricsSchemaUri()); + System.out.format("\tMetrics: %s\n", modelEvaluation.getMetrics()); + System.out.format("\tCreate Time: %s\n", modelEvaluation.getCreateTime()); + System.out.format("\tSlice Dimensions: %s\n", modelEvaluation.getSliceDimensionsList()); + } + } +} +// [END aiplatform_get_model_evaluation_text_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationTextEntityExtractionSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationTextEntityExtractionSample.java new file mode 100644 index 00000000000..ac9164b9267 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationTextEntityExtractionSample.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_text_entity_extraction_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationTextEntityExtractionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + + getModelEvaluationTextEntityExtractionSample(project, modelId, evaluationId); + } + + static void getModelEvaluationTextEntityExtractionSample( + String project, String modelId, String evaluationId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + ModelEvaluation modelEvaluation = modelServiceClient.getModelEvaluation(modelEvaluationName); + + System.out.println("Get Model Evaluation Text Entity Extraction Response"); + System.out.format("\tModel Name: %s\n", modelEvaluation.getName()); + System.out.format("\tMetrics Schema Uri: %s\n", modelEvaluation.getMetricsSchemaUri()); + System.out.format("\tMetrics: %s\n", modelEvaluation.getMetrics()); + System.out.format("\tCreate Time: %s\n", modelEvaluation.getCreateTime()); + System.out.format("\tSlice Dimensions: %s\n", modelEvaluation.getSliceDimensionsList()); + } + } +} +// [END aiplatform_get_model_evaluation_text_entity_extraction_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationTextSentimentAnalysisSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationTextSentimentAnalysisSample.java new file mode 100644 index 00000000000..81d686e2186 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationTextSentimentAnalysisSample.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_text_sentiment_analysis_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationTextSentimentAnalysisSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + + getModelEvaluationTextSentimentAnalysisSample(project, modelId, evaluationId); + } + + static void getModelEvaluationTextSentimentAnalysisSample( + String project, String modelId, String evaluationId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + ModelEvaluation modelEvaluation = modelServiceClient.getModelEvaluation(modelEvaluationName); + + System.out.println("Get Model Evaluation Text Sentiment Analysis Response"); + System.out.format("\tModel Name: %s\n", modelEvaluation.getName()); + System.out.format("\tMetrics Schema Uri: %s\n", modelEvaluation.getMetricsSchemaUri()); + System.out.format("\tMetrics: %s\n", modelEvaluation.getMetrics()); + System.out.format("\tCreate Time: %s\n", modelEvaluation.getCreateTime()); + System.out.format("\tSlice Dimensions: %s\n", modelEvaluation.getSliceDimensionsList()); + } + } +} +// [END aiplatform_get_model_evaluation_text_sentiment_analysis_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoActionRecognitionSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoActionRecognitionSample.java new file mode 100644 index 00000000000..01748a85ea7 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoActionRecognitionSample.java @@ -0,0 +1,68 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_video_action_recognition_sample] +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationVideoActionRecognitionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "PROJECT"; + String modelId = "MODEL_ID"; + String evaluationId = "EVALUATION_ID"; + getModelEvaluationVideoActionRecognitionSample(project, modelId, evaluationId); + } + + static void getModelEvaluationVideoActionRecognitionSample( + String project, String modelId, String evaluationId) throws IOException { + ModelServiceSettings settings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient client = ModelServiceClient.create(settings)) { + ModelEvaluationName name = ModelEvaluationName.of(project, location, modelId, evaluationId); + ModelEvaluation response = client.getModelEvaluation(name); + System.out.format("response: %s\n", response); + } + } +} + +// [END aiplatform_get_model_evaluation_video_action_recognition_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoClassificationSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoClassificationSample.java new file mode 100644 index 00000000000..4e4babc5e6f --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoClassificationSample.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_video_classification_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationVideoClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + getModelEvaluationVideoClassification(project, modelId, evaluationId); + } + + static void getModelEvaluationVideoClassification( + String project, String modelId, String evaluationId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + + ModelEvaluation modelEvaluation = modelServiceClient.getModelEvaluation(modelEvaluationName); + + System.out.println("Get Model Evaluation Video Classification Response"); + System.out.format("Name: %s\n", modelEvaluation.getName()); + System.out.format("Metrics Schema Uri: %s\n", modelEvaluation.getMetricsSchemaUri()); + System.out.format("Metrics: %s\n", modelEvaluation.getMetrics()); + System.out.format("Create Time: %s\n", modelEvaluation.getCreateTime()); + System.out.format("Slice Dimensions: %s\n", modelEvaluation.getSliceDimensionsList()); + } + } +} +// [END aiplatform_get_model_evaluation_video_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoObjectTrackingSample.java b/aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoObjectTrackingSample.java new file mode 100644 index 00000000000..a095c9a262e --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelEvaluationVideoObjectTrackingSample.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_evaluation_object_tracking_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluation; +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class GetModelEvaluationVideoObjectTrackingSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + getModelEvaluationVideoObjectTracking(project, modelId, evaluationId); + } + + static void getModelEvaluationVideoObjectTracking( + String project, String modelId, String evaluationId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + + ModelEvaluation modelEvaluation = modelServiceClient.getModelEvaluation(modelEvaluationName); + + System.out.println("Get Model Evaluation Video Object Tracking Response"); + System.out.format("Name: %s\n", modelEvaluation.getName()); + System.out.format("Metrics Schema Uri: %s\n", modelEvaluation.getMetricsSchemaUri()); + System.out.format("Metrics: %s\n", modelEvaluation.getMetrics()); + System.out.format("Create Time: %s\n", modelEvaluation.getCreateTime()); + System.out.format("Slice Dimensions: %s\n", modelEvaluation.getSliceDimensionsList()); + } + } +} +// [END aiplatform_get_model_evaluation_object_tracking_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetModelSample.java b/aiplatform/src/main/java/aiplatform/GetModelSample.java new file mode 100644 index 00000000000..5222db4b86b --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetModelSample.java @@ -0,0 +1,120 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_model_sample] + +import com.google.cloud.aiplatform.v1.DeployedModelRef; +import com.google.cloud.aiplatform.v1.EnvVar; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.Model.ExportFormat; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import com.google.cloud.aiplatform.v1.Port; +import com.google.cloud.aiplatform.v1.PredictSchemata; +import java.io.IOException; + +public class GetModelSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + getModelSample(project, modelId); + } + + static void getModelSample(String project, String modelId) throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelName modelName = ModelName.of(project, location, modelId); + + Model modelResponse = modelServiceClient.getModel(modelName); + System.out.println("Get Model response"); + System.out.format("\tName: %s\n", modelResponse.getName()); + System.out.format("\tDisplay Name: %s\n", modelResponse.getDisplayName()); + System.out.format("\tDescription: %s\n", modelResponse.getDescription()); + + System.out.format("\tMetadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("\tMetadata: %s\n", modelResponse.getMetadata()); + System.out.format("\tTraining Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("\tArtifact Uri: %s\n", modelResponse.getArtifactUri()); + + System.out.format( + "\tSupported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList()); + System.out.format( + "\tSupported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList()); + System.out.format( + "\tSupported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList()); + + System.out.format("\tCreate Time: %s\n", modelResponse.getCreateTime()); + System.out.format("\tUpdate Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", modelResponse.getLabelsMap()); + + PredictSchemata predictSchemata = modelResponse.getPredictSchemata(); + System.out.println("\tPredict Schemata"); + System.out.format("\t\tInstance Schema Uri: %s\n", predictSchemata.getInstanceSchemaUri()); + System.out.format( + "\t\tParameters Schema Uri: %s\n", predictSchemata.getParametersSchemaUri()); + System.out.format( + "\t\tPrediction Schema Uri: %s\n", predictSchemata.getPredictionSchemaUri()); + + for (ExportFormat exportFormat : modelResponse.getSupportedExportFormatsList()) { + System.out.println("\tSupported Export Format"); + System.out.format("\t\tId: %s\n", exportFormat.getId()); + } + + ModelContainerSpec containerSpec = modelResponse.getContainerSpec(); + System.out.println("\tContainer Spec"); + System.out.format("\t\tImage Uri: %s\n", containerSpec.getImageUri()); + System.out.format("\t\tCommand: %s\n", containerSpec.getCommandList()); + System.out.format("\t\tArgs: %s\n", containerSpec.getArgsList()); + System.out.format("\t\tPredict Route: %s\n", containerSpec.getPredictRoute()); + System.out.format("\t\tHealth Route: %s\n", containerSpec.getHealthRoute()); + + for (EnvVar envVar : containerSpec.getEnvList()) { + System.out.println("\t\tEnv"); + System.out.format("\t\t\tName: %s\n", envVar.getName()); + System.out.format("\t\t\tValue: %s\n", envVar.getValue()); + } + + for (Port port : containerSpec.getPortsList()) { + System.out.println("\t\tPort"); + System.out.format("\t\t\tContainer Port: %s\n", port.getContainerPort()); + } + + for (DeployedModelRef deployedModelRef : modelResponse.getDeployedModelsList()) { + System.out.println("\tDeployed Model"); + System.out.format("\t\tEndpoint: %s\n", deployedModelRef.getEndpoint()); + System.out.format("\t\tDeployed Model Id: %s\n", deployedModelRef.getDeployedModelId()); + } + } + } +} +// [END aiplatform_get_model_sample] diff --git a/aiplatform/src/main/java/aiplatform/GetTrainingPipelineSample.java b/aiplatform/src/main/java/aiplatform/GetTrainingPipelineSample.java new file mode 100644 index 00000000000..11850291b5f --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/GetTrainingPipelineSample.java @@ -0,0 +1,177 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_get_training_pipeline_sample] + +import com.google.cloud.aiplatform.v1.DeployedModelRef; +import com.google.cloud.aiplatform.v1.EnvVar; +import com.google.cloud.aiplatform.v1.FilterSplit; +import com.google.cloud.aiplatform.v1.FractionSplit; +import com.google.cloud.aiplatform.v1.InputDataConfig; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.Port; +import com.google.cloud.aiplatform.v1.PredefinedSplit; +import com.google.cloud.aiplatform.v1.PredictSchemata; +import com.google.cloud.aiplatform.v1.TimestampSplit; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.cloud.aiplatform.v1.TrainingPipelineName; +import com.google.rpc.Status; +import java.io.IOException; + +public class GetTrainingPipelineSample { + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String trainingPipelineId = "YOUR_TRAINING_PIPELINE_ID"; + getTrainingPipeline(project, trainingPipelineId); + } + + static void getTrainingPipeline(String project, String trainingPipelineId) throws IOException { + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + TrainingPipelineName trainingPipelineName = + TrainingPipelineName.of(project, location, trainingPipelineId); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.getTrainingPipeline(trainingPipelineName); + + System.out.println("Get Training Pipeline Response"); + System.out.format("\tName: %s\n", trainingPipelineResponse.getName()); + System.out.format("\tDisplay Name: %s\n", trainingPipelineResponse.getDisplayName()); + System.out.format( + "\tTraining Task Definition: %s\n", trainingPipelineResponse.getTrainingTaskDefinition()); + System.out.format( + "\tTraining Task Inputs: %s\n", trainingPipelineResponse.getTrainingTaskInputs()); + System.out.format( + "\tTraining Task Metadata: %s\n", trainingPipelineResponse.getTrainingTaskMetadata()); + System.out.format("\tState: %s\n", trainingPipelineResponse.getState()); + System.out.format("\tCreate Time: %s\n", trainingPipelineResponse.getCreateTime()); + System.out.format("\tStart Time: %s\n", trainingPipelineResponse.getStartTime()); + System.out.format("\tEnd Time: %s\n", trainingPipelineResponse.getEndTime()); + System.out.format("\tUpdate Time: %s\n", trainingPipelineResponse.getUpdateTime()); + System.out.format("\tLabels: %s\n", trainingPipelineResponse.getLabelsMap()); + InputDataConfig inputDataConfig = trainingPipelineResponse.getInputDataConfig(); + + System.out.println("\tInput Data Config"); + System.out.format("\t\tDataset Id: %s\n", inputDataConfig.getDatasetId()); + System.out.format("\t\tAnnotations Filter: %s\n", inputDataConfig.getAnnotationsFilter()); + FractionSplit fractionSplit = inputDataConfig.getFractionSplit(); + + System.out.println("\t\tFraction Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", fractionSplit.getTrainingFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", fractionSplit.getValidationFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", fractionSplit.getTestFraction()); + FilterSplit filterSplit = inputDataConfig.getFilterSplit(); + + System.out.println("\t\tFilter Split"); + System.out.format("\t\t\tTraining Filter: %s\n", filterSplit.getTrainingFilter()); + System.out.format("\t\t\tValidation Filter: %s\n", filterSplit.getValidationFilter()); + System.out.format("\t\t\tTest Filter: %s\n", filterSplit.getTestFilter()); + PredefinedSplit predefinedSplit = inputDataConfig.getPredefinedSplit(); + + System.out.println("\t\tPredefined Split"); + System.out.format("\t\t\tKey: %s\n", predefinedSplit.getKey()); + TimestampSplit timestampSplit = inputDataConfig.getTimestampSplit(); + + System.out.println("\t\tTimestamp Split"); + System.out.format("\t\t\tTraining Fraction: %s\n", timestampSplit.getTrainingFraction()); + System.out.format("\t\t\tTest Fraction: %s\n", timestampSplit.getTestFraction()); + System.out.format("\t\t\tValidation Fraction: %s\n", timestampSplit.getValidationFraction()); + System.out.format("\t\t\tKey: %s\n", timestampSplit.getKey()); + Model modelResponse = trainingPipelineResponse.getModelToUpload(); + + System.out.println("\t\tModel to upload"); + System.out.format("\t\tName: %s\n", modelResponse.getName()); + System.out.format("\t\tDisplay Name: %s\n", modelResponse.getDisplayName()); + System.out.format("\t\tDescription: %s\n", modelResponse.getDescription()); + System.out.format("\t\tMetadata Schema Uri: %s\n", modelResponse.getMetadataSchemaUri()); + System.out.format("\t\tMeta Data: %s\n", modelResponse.getMetadata()); + System.out.format("\t\tTraining Pipeline: %s\n", modelResponse.getTrainingPipeline()); + System.out.format("\t\tArtifact Uri: %s\n", modelResponse.getArtifactUri()); + System.out.format( + "\t\tSupported Deployment Resources Types: %s\n", + modelResponse.getSupportedDeploymentResourcesTypesList().toString()); + System.out.format( + "\t\tSupported Input Storage Formats: %s\n", + modelResponse.getSupportedInputStorageFormatsList().toString()); + System.out.format( + "\t\tSupported Output Storage Formats: %s\n", + modelResponse.getSupportedOutputStorageFormatsList().toString()); + System.out.format("\t\tCreate Time: %s\n", modelResponse.getCreateTime()); + System.out.format("\t\tUpdate Time: %s\n", modelResponse.getUpdateTime()); + System.out.format("\t\tLabels: %s\n", modelResponse.getLabelsMap()); + PredictSchemata predictSchemata = modelResponse.getPredictSchemata(); + + System.out.println("\tPredict Schemata"); + System.out.format("\t\tInstance Schema Uri: %s\n", predictSchemata.getInstanceSchemaUri()); + System.out.format( + "\t\tParameters Schema Uri: %s\n", predictSchemata.getParametersSchemaUri()); + System.out.format( + "\t\tPrediction Schema Uri: %s\n", predictSchemata.getPredictionSchemaUri()); + + for (Model.ExportFormat supportedExportFormat : + modelResponse.getSupportedExportFormatsList()) { + System.out.println("\tSupported Export Format"); + System.out.format("\t\tId: %s\n", supportedExportFormat.getId()); + } + ModelContainerSpec containerSpec = modelResponse.getContainerSpec(); + + System.out.println("\tContainer Spec"); + System.out.format("\t\tImage Uri: %s\n", containerSpec.getImageUri()); + System.out.format("\t\tCommand: %s\n", containerSpec.getCommandList()); + System.out.format("\t\tArgs: %s\n", containerSpec.getArgsList()); + System.out.format("\t\tPredict Route: %s\n", containerSpec.getPredictRoute()); + System.out.format("\t\tHealth Route: %s\n", containerSpec.getHealthRoute()); + + for (EnvVar envVar : containerSpec.getEnvList()) { + System.out.println("\t\tEnv"); + System.out.format("\t\t\tName: %s\n", envVar.getName()); + System.out.format("\t\t\tValue: %s\n", envVar.getValue()); + } + + for (Port port : containerSpec.getPortsList()) { + System.out.println("\t\tPort"); + System.out.format("\t\t\tContainer Port: %s\n", port.getContainerPort()); + } + + for (DeployedModelRef deployedModelRef : modelResponse.getDeployedModelsList()) { + System.out.println("\tDeployed Model"); + System.out.format("\t\tEndpoint: %s\n", deployedModelRef.getEndpoint()); + System.out.format("\t\tDeployed Model Id: %s\n", deployedModelRef.getDeployedModelId()); + } + + Status status = trainingPipelineResponse.getError(); + System.out.println("\tError"); + System.out.format("\t\tCode: %s\n", status.getCode()); + System.out.format("\t\tMessage: %s\n", status.getMessage()); + } + } +} +// [END aiplatform_get_training_pipeline_sample] diff --git a/aiplatform/src/main/java/aiplatform/ImportDataImageClassificationSample.java b/aiplatform/src/main/java/aiplatform/ImportDataImageClassificationSample.java new file mode 100644 index 00000000000..f3c4e3ed03d --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ImportDataImageClassificationSample.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_import_data_image_classification_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.ImportDataConfig; +import com.google.cloud.aiplatform.v1.ImportDataOperationMetadata; +import com.google.cloud.aiplatform.v1.ImportDataResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ImportDataImageClassificationSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String gcsSourceUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_image_source/[file.csv/file.jsonl]"; + importDataImageClassificationSample(project, datasetId, gcsSourceUri); + } + + static void importDataImageClassificationSample( + String project, String datasetId, String gcsSourceUri) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + String importSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/ioformat/" + + "image_classification_single_label_io_format_1.0.0.yaml"; + + GcsSource.Builder gcsSource = GcsSource.newBuilder(); + gcsSource.addUris(gcsSourceUri); + DatasetName datasetName = DatasetName.of(project, location, datasetId); + + List importDataConfigList = + Collections.singletonList( + ImportDataConfig.newBuilder() + .setGcsSource(gcsSource) + .setImportSchemaUri(importSchemaUri) + .build()); + + OperationFuture importDataResponseFuture = + datasetServiceClient.importDataAsync(datasetName, importDataConfigList); + System.out.format( + "Operation name: %s\n", importDataResponseFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + ImportDataResponse importDataResponse = importDataResponseFuture.get(300, TimeUnit.SECONDS); + + System.out.format( + "Import Data Image Classification Response: %s\n", importDataResponse.toString()); + } + } +} +// [END aiplatform_import_data_image_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/ImportDataImageObjectDetectionSample.java b/aiplatform/src/main/java/aiplatform/ImportDataImageObjectDetectionSample.java new file mode 100644 index 00000000000..78f7551945f --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ImportDataImageObjectDetectionSample.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_import_data_image_object_detection_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.ImportDataConfig; +import com.google.cloud.aiplatform.v1.ImportDataOperationMetadata; +import com.google.cloud.aiplatform.v1.ImportDataResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ImportDataImageObjectDetectionSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String gcsSourceUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_image_source/[file.csv/file.jsonl]"; + importDataImageObjectDetectionSample(project, datasetId, gcsSourceUri); + } + + static void importDataImageObjectDetectionSample( + String project, String datasetId, String gcsSourceUri) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + String importSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/ioformat/" + + "image_bounding_box_io_format_1.0.0.yaml"; + GcsSource.Builder gcsSource = GcsSource.newBuilder(); + gcsSource.addUris(gcsSourceUri); + DatasetName datasetName = DatasetName.of(project, location, datasetId); + + List importDataConfigList = + Collections.singletonList( + ImportDataConfig.newBuilder() + .setGcsSource(gcsSource) + .setImportSchemaUri(importSchemaUri) + .build()); + + OperationFuture importDataResponseFuture = + datasetServiceClient.importDataAsync(datasetName, importDataConfigList); + System.out.format( + "Operation name: %s\n", importDataResponseFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + ImportDataResponse importDataResponse = importDataResponseFuture.get(300, TimeUnit.SECONDS); + + System.out.format( + "Import Data Image Object Detection Response: %s\n", importDataResponse.toString()); + } + } +} +// [END aiplatform_import_data_image_object_detection_sample] diff --git a/aiplatform/src/main/java/aiplatform/ImportDataTextClassificationSingleLabelSample.java b/aiplatform/src/main/java/aiplatform/ImportDataTextClassificationSingleLabelSample.java new file mode 100644 index 00000000000..696fdeb5842 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ImportDataTextClassificationSingleLabelSample.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_import_data_text_classification_single_label_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.ImportDataConfig; +import com.google.cloud.aiplatform.v1.ImportDataOperationMetadata; +import com.google.cloud.aiplatform.v1.ImportDataResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ImportDataTextClassificationSingleLabelSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String gcsSourceUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_text_source/[file.csv/file.jsonl]"; + + importDataTextClassificationSingleLabelSample(project, datasetId, gcsSourceUri); + } + + static void importDataTextClassificationSingleLabelSample( + String project, String datasetId, String gcsSourceUri) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + String importSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/ioformat/" + + "text_classification_single_label_io_format_1.0.0.yaml"; + + GcsSource.Builder gcsSource = GcsSource.newBuilder(); + gcsSource.addUris(gcsSourceUri); + DatasetName datasetName = DatasetName.of(project, location, datasetId); + + List importDataConfigList = + Collections.singletonList( + ImportDataConfig.newBuilder() + .setGcsSource(gcsSource) + .setImportSchemaUri(importSchemaUri) + .build()); + + OperationFuture importDataResponseFuture = + datasetServiceClient.importDataAsync(datasetName, importDataConfigList); + System.out.format( + "Operation name: %s\n", importDataResponseFuture.getInitialFuture().get().getName()); + + System.out.println("Waiting for operation to finish..."); + ImportDataResponse importDataResponse = importDataResponseFuture.get(300, TimeUnit.SECONDS); + System.out.format( + "Import Data Text Classification Response: %s\n", importDataResponse.toString()); + } + } +} +// [END aiplatform_import_data_text_classification_single_label_sample] diff --git a/aiplatform/src/main/java/aiplatform/ImportDataTextEntityExtractionSample.java b/aiplatform/src/main/java/aiplatform/ImportDataTextEntityExtractionSample.java new file mode 100644 index 00000000000..2a8ee01a886 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ImportDataTextEntityExtractionSample.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_import_data_text_entity_extraction_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.ImportDataConfig; +import com.google.cloud.aiplatform.v1.ImportDataOperationMetadata; +import com.google.cloud.aiplatform.v1.ImportDataResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ImportDataTextEntityExtractionSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String gcsSourceUri = "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_text_source/[file.jsonl]"; + + importDataTextEntityExtractionSample(project, datasetId, gcsSourceUri); + } + + static void importDataTextEntityExtractionSample( + String project, String datasetId, String gcsSourceUri) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + String importSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/ioformat/" + + "text_extraction_io_format_1.0.0.yaml"; + + GcsSource.Builder gcsSource = GcsSource.newBuilder(); + gcsSource.addUris(gcsSourceUri); + DatasetName datasetName = DatasetName.of(project, location, datasetId); + + List importDataConfigList = + Collections.singletonList( + ImportDataConfig.newBuilder() + .setGcsSource(gcsSource) + .setImportSchemaUri(importSchemaUri) + .build()); + + OperationFuture importDataResponseFuture = + datasetServiceClient.importDataAsync(datasetName, importDataConfigList); + System.out.format( + "Operation name: %s\n", importDataResponseFuture.getInitialFuture().get().getName()); + + System.out.println("Waiting for operation to finish..."); + ImportDataResponse importDataResponse = importDataResponseFuture.get(300, TimeUnit.SECONDS); + System.out.format( + "Import Data Text Entity Extraction Response: %s\n", importDataResponse.toString()); + } + } +} +// [END aiplatform_import_data_text_entity_extraction_sample] diff --git a/aiplatform/src/main/java/aiplatform/ImportDataTextSentimentAnalysisSample.java b/aiplatform/src/main/java/aiplatform/ImportDataTextSentimentAnalysisSample.java new file mode 100644 index 00000000000..064fb6eb207 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ImportDataTextSentimentAnalysisSample.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_import_data_text_sentiment_analysis_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.ImportDataConfig; +import com.google.cloud.aiplatform.v1.ImportDataOperationMetadata; +import com.google.cloud.aiplatform.v1.ImportDataResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ImportDataTextSentimentAnalysisSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + String gcsSourceUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_text_source/[file.csv/file.jsonl]"; + + importDataTextSentimentAnalysisSample(project, datasetId, gcsSourceUri); + } + + static void importDataTextSentimentAnalysisSample( + String project, String datasetId, String gcsSourceUri) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + String importSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/ioformat/" + + "text_sentiment_io_format_1.0.0.yaml"; + + GcsSource.Builder gcsSource = GcsSource.newBuilder(); + gcsSource.addUris(gcsSourceUri); + DatasetName datasetName = DatasetName.of(project, location, datasetId); + + List importDataConfigList = + Collections.singletonList( + ImportDataConfig.newBuilder() + .setGcsSource(gcsSource) + .setImportSchemaUri(importSchemaUri) + .build()); + + OperationFuture importDataResponseFuture = + datasetServiceClient.importDataAsync(datasetName, importDataConfigList); + System.out.format( + "Operation name: %s\n", importDataResponseFuture.getInitialFuture().get().getName()); + + System.out.println("Waiting for operation to finish..."); + ImportDataResponse importDataResponse = importDataResponseFuture.get(300, TimeUnit.SECONDS); + System.out.format( + "Import Data Text Sentiment Analysis Response: %s\n", importDataResponse.toString()); + } + } +} +// [END aiplatform_import_data_text_sentiment_analysis_sample] diff --git a/aiplatform/src/main/java/aiplatform/ImportDataVideoActionRecognitionSample.java b/aiplatform/src/main/java/aiplatform/ImportDataVideoActionRecognitionSample.java new file mode 100644 index 00000000000..7bede6dfc4c --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ImportDataVideoActionRecognitionSample.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_import_data_video_action_recognition_sample] +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.ImportDataConfig; +import com.google.cloud.aiplatform.v1.ImportDataOperationMetadata; +import com.google.cloud.aiplatform.v1.ImportDataResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; + +public class ImportDataVideoActionRecognitionSample { + + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException { + // TODO(developer): Replace these variables before running the sample. + String project = "PROJECT"; + String datasetId = "DATASET_ID"; + String gcsSourceUri = "GCS_SOURCE_URI"; + importDataVideoActionRecognitionSample(project, datasetId, gcsSourceUri); + } + + static void importDataVideoActionRecognitionSample( + String project, String datasetId, String gcsSourceUri) + throws IOException, ExecutionException, InterruptedException { + DatasetServiceSettings settings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + String location = "us-central1"; + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient client = DatasetServiceClient.create(settings)) { + GcsSource gcsSource = GcsSource.newBuilder().addUris(gcsSourceUri).build(); + ImportDataConfig importConfig0 = + ImportDataConfig.newBuilder() + .setGcsSource(gcsSource) + .setImportSchemaUri( + "gs://google-cloud-aiplatform/schema/dataset/ioformat/" + + "video_action_recognition_io_format_1.0.0.yaml") + .build(); + List importConfigs = new ArrayList<>(); + importConfigs.add(importConfig0); + DatasetName name = DatasetName.of(project, location, datasetId); + OperationFuture response = + client.importDataAsync(name, importConfigs); + + // You can use OperationFuture.getInitialFuture to get a future representing the initial + // response to the request, which contains information while the operation is in progress. + System.out.format("Operation name: %s\n", response.getInitialFuture().get().getName()); + + // OperationFuture.get() will block until the operation is finished. + ImportDataResponse importDataResponse = response.get(); + System.out.format("importDataResponse: %s\n", importDataResponse); + } + } +} + +// [END aiplatform_import_data_video_action_recognition_sample] diff --git a/aiplatform/src/main/java/aiplatform/ImportDataVideoClassificationSample.java b/aiplatform/src/main/java/aiplatform/ImportDataVideoClassificationSample.java new file mode 100644 index 00000000000..16cbc79e9a8 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ImportDataVideoClassificationSample.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_import_data_video_classification_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.ImportDataConfig; +import com.google.cloud.aiplatform.v1.ImportDataOperationMetadata; +import com.google.cloud.aiplatform.v1.ImportDataResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ImportDataVideoClassificationSample { + + public static void main(String[] args) + throws InterruptedException, ExecutionException, TimeoutException, IOException { + // TODO(developer): Replace these variables before running the sample. + String gcsSourceUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_video_source/[file.csv/file.jsonl]"; + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + importDataVideoClassification(gcsSourceUri, project, datasetId); + } + + static void importDataVideoClassification(String gcsSourceUri, String project, String datasetId) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + String importSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/ioformat/" + + "video_classification_io_format_1.0.0.yaml"; + + GcsSource.Builder gcsSource = GcsSource.newBuilder(); + gcsSource.addUris(gcsSourceUri); + + DatasetName datasetName = DatasetName.of(project, location, datasetId); + List importDataConfigs = + Collections.singletonList( + ImportDataConfig.newBuilder() + .setGcsSource(gcsSource) + .setImportSchemaUri(importSchemaUri) + .build()); + + OperationFuture importDataResponseFuture = + datasetServiceClient.importDataAsync(datasetName, importDataConfigs); + System.out.format( + "Operation name: %s\n", importDataResponseFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + ImportDataResponse importDataResponse = importDataResponseFuture.get(1800, TimeUnit.SECONDS); + + System.out.format( + "Import Data Video Classification Response: %s\n", importDataResponse.toString()); + } + } +} +// [END aiplatform_import_data_video_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/ImportDataVideoObjectTrackingSample.java b/aiplatform/src/main/java/aiplatform/ImportDataVideoObjectTrackingSample.java new file mode 100644 index 00000000000..ce099b95845 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ImportDataVideoObjectTrackingSample.java @@ -0,0 +1,86 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_import_data_video_object_tracking_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.DatasetName; +import com.google.cloud.aiplatform.v1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.ImportDataConfig; +import com.google.cloud.aiplatform.v1.ImportDataOperationMetadata; +import com.google.cloud.aiplatform.v1.ImportDataResponse; +import java.io.IOException; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ImportDataVideoObjectTrackingSample { + + public static void main(String[] args) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + String gcsSourceUri = + "gs://YOUR_GCS_SOURCE_BUCKET/path_to_your_video_source/[file.csv/file.jsonl]"; + String project = "YOUR_PROJECT_ID"; + String datasetId = "YOUR_DATASET_ID"; + importDataVideObjectTracking(gcsSourceUri, project, datasetId); + } + + static void importDataVideObjectTracking(String gcsSourceUri, String project, String datasetId) + throws IOException, ExecutionException, InterruptedException, TimeoutException { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String location = "us-central1"; + String importSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/ioformat/" + + "video_object_tracking_io_format_1.0.0.yaml"; + + GcsSource.Builder gcsSource = GcsSource.newBuilder(); + gcsSource.addUris(gcsSourceUri); + DatasetName datasetName = DatasetName.of(project, location, datasetId); + List importDataConfigs = + Collections.singletonList( + ImportDataConfig.newBuilder() + .setGcsSource(gcsSource) + .setImportSchemaUri(importSchemaUri) + .build()); + + OperationFuture importDataResponseFuture = + datasetServiceClient.importDataAsync(datasetName, importDataConfigs); + System.out.format( + "Operation name: %s\n", importDataResponseFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + ImportDataResponse importDataResponse = importDataResponseFuture.get(300, TimeUnit.SECONDS); + + System.out.format( + "Import Data Video Object Tracking Response: %s\n", importDataResponse.toString()); + } + } +} +// [END aiplatform_import_data_video_object_tracking_sample] diff --git a/aiplatform/src/main/java/aiplatform/ImportFeatureValuesSample.java b/aiplatform/src/main/java/aiplatform/ImportFeatureValuesSample.java new file mode 100644 index 00000000000..405b05f54fb --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ImportFeatureValuesSample.java @@ -0,0 +1,122 @@ +/* + * 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. + * + * + * Bulk import values into a featurestore for existing features. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_import_feature_values_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.AvroSource; +import com.google.cloud.aiplatform.v1.EntityTypeName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.GcsSource; +import com.google.cloud.aiplatform.v1.ImportFeatureValuesOperationMetadata; +import com.google.cloud.aiplatform.v1.ImportFeatureValuesRequest; +import com.google.cloud.aiplatform.v1.ImportFeatureValuesRequest.FeatureSpec; +import com.google.cloud.aiplatform.v1.ImportFeatureValuesResponse; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class ImportFeatureValuesSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String entityIdField = "YOUR_ENTITY_FIELD_ID"; + String featureTimeField = "YOUR_FEATURE_TIME_FIELD"; + String gcsSourceUri = "YOUR_GCS_SOURCE_URI"; + int workerCount = 2; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 300; + importFeatureValuesSample( + project, + featurestoreId, + entityTypeId, + gcsSourceUri, + entityIdField, + featureTimeField, + workerCount, + location, + endpoint, + timeout); + } + + static void importFeatureValuesSample( + String project, + String featurestoreId, + String entityTypeId, + String gcsSourceUri, + String entityIdField, + String featureTimeField, + int workerCount, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + List featureSpecs = new ArrayList<>(); + + featureSpecs.add(FeatureSpec.newBuilder().setId("title").build()); + featureSpecs.add(FeatureSpec.newBuilder().setId("genres").build()); + featureSpecs.add(FeatureSpec.newBuilder().setId("average_rating").build()); + ImportFeatureValuesRequest importFeatureValuesRequest = + ImportFeatureValuesRequest.newBuilder() + .setEntityType( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .setEntityIdField(entityIdField) + .setFeatureTimeField(featureTimeField) + .addAllFeatureSpecs(featureSpecs) + .setWorkerCount(workerCount) + .setAvroSource( + AvroSource.newBuilder() + .setGcsSource(GcsSource.newBuilder().addUris(gcsSourceUri))) + .build(); + OperationFuture + importFeatureValuesFuture = + featurestoreServiceClient.importFeatureValuesAsync(importFeatureValuesRequest); + System.out.format( + "Operation name: %s%n", importFeatureValuesFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + ImportFeatureValuesResponse importFeatureValuesResponse = + importFeatureValuesFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Import Feature Values Response"); + System.out.println(importFeatureValuesResponse); + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_import_feature_values_sample] diff --git a/aiplatform/src/main/java/aiplatform/ListEntityTypesAsyncSample.java b/aiplatform/src/main/java/aiplatform/ListEntityTypesAsyncSample.java new file mode 100644 index 00000000000..b429a642c53 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ListEntityTypesAsyncSample.java @@ -0,0 +1,80 @@ +/* + * 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. + * + * + * List available entity type details of an existing featurestore resource. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_list_entity_types_async_sample] + +import com.google.cloud.aiplatform.v1.EntityType; +import com.google.cloud.aiplatform.v1.FeaturestoreName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.ListEntityTypesRequest; +import com.google.cloud.aiplatform.v1.ListEntityTypesResponse; +import com.google.common.base.Strings; +import java.io.IOException; + +public class ListEntityTypesAsyncSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + listEntityTypesAsyncSample(project, featurestoreId, location, endpoint); + } + + static void listEntityTypesAsyncSample( + String project, String featurestoreId, String location, String endpoint) throws IOException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + ListEntityTypesRequest listEntityTypeRequest = + ListEntityTypesRequest.newBuilder() + .setParent(FeaturestoreName.of(project, location, featurestoreId).toString()) + .build(); + System.out.println("List Entity Types Async Response"); + while (true) { + ListEntityTypesResponse listEntityTypesResponse = + featurestoreServiceClient.listEntityTypesCallable().call(listEntityTypeRequest); + for (EntityType element : listEntityTypesResponse.getEntityTypesList()) { + System.out.println(element); + } + String nextPageToken = listEntityTypesResponse.getNextPageToken(); + if (!Strings.isNullOrEmpty(nextPageToken)) { + listEntityTypeRequest = + listEntityTypeRequest.toBuilder().setPageToken(nextPageToken).build(); + } else { + break; + } + } + } + } +} +// [END aiplatform_list_entity_types_async_sample] diff --git a/aiplatform/src/main/java/aiplatform/ListEntityTypesSample.java b/aiplatform/src/main/java/aiplatform/ListEntityTypesSample.java new file mode 100644 index 00000000000..1160216c4b8 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ListEntityTypesSample.java @@ -0,0 +1,68 @@ +/* + * 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. + * + * + * List available entity type details of an existing featurestore resource. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_list_entity_types_sample] + +import com.google.cloud.aiplatform.v1.EntityType; +import com.google.cloud.aiplatform.v1.FeaturestoreName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.ListEntityTypesRequest; +import java.io.IOException; + +public class ListEntityTypesSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + listEntityTypesSample(project, featurestoreId, location, endpoint); + } + + static void listEntityTypesSample( + String project, String featurestoreId, String location, String endpoint) throws IOException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + ListEntityTypesRequest listEntityTypeRequest = + ListEntityTypesRequest.newBuilder() + .setParent(FeaturestoreName.of(project, location, featurestoreId).toString()) + .build(); + System.out.println("List Entity Types Response"); + for (EntityType element : + featurestoreServiceClient.listEntityTypes(listEntityTypeRequest).iterateAll()) { + System.out.println(element); + } + } + } +} +// [END aiplatform_list_entity_types_sample] diff --git a/aiplatform/src/main/java/aiplatform/ListFeaturesAsyncSample.java b/aiplatform/src/main/java/aiplatform/ListFeaturesAsyncSample.java new file mode 100644 index 00000000000..5cc41ec8cd7 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ListFeaturesAsyncSample.java @@ -0,0 +1,83 @@ +/* + * 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. + * + * + * List available feature details. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_list_features_async_sample] + +import com.google.cloud.aiplatform.v1.EntityTypeName; +import com.google.cloud.aiplatform.v1.Feature; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.ListFeaturesRequest; +import com.google.cloud.aiplatform.v1.ListFeaturesResponse; +import com.google.common.base.Strings; +import java.io.IOException; + +public class ListFeaturesAsyncSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + + listFeaturesAsyncSample(project, featurestoreId, entityTypeId, location, endpoint); + } + + static void listFeaturesAsyncSample( + String project, String featurestoreId, String entityTypeId, String location, String endpoint) + throws IOException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + ListFeaturesRequest listFeaturesRequest = + ListFeaturesRequest.newBuilder() + .setParent( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .build(); + System.out.println("List Features Async Response"); + while (true) { + ListFeaturesResponse listFeaturesResponse = + featurestoreServiceClient.listFeaturesCallable().call(listFeaturesRequest); + for (Feature element : listFeaturesResponse.getFeaturesList()) { + System.out.println(element); + } + String nextPageToken = listFeaturesResponse.getNextPageToken(); + if (!Strings.isNullOrEmpty(nextPageToken)) { + listFeaturesRequest = listFeaturesRequest.toBuilder().setPageToken(nextPageToken).build(); + } else { + break; + } + } + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_list_features_async_sample] diff --git a/aiplatform/src/main/java/aiplatform/ListFeaturesSample.java b/aiplatform/src/main/java/aiplatform/ListFeaturesSample.java new file mode 100644 index 00000000000..b17eeb35e48 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ListFeaturesSample.java @@ -0,0 +1,72 @@ +/* + * 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. + * + * + * List available feature details. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_list_features_sample] + +import com.google.cloud.aiplatform.v1.EntityTypeName; +import com.google.cloud.aiplatform.v1.Feature; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.ListFeaturesRequest; +import java.io.IOException; + +public class ListFeaturesSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + + listFeaturesSample(project, featurestoreId, entityTypeId, location, endpoint); + } + + static void listFeaturesSample( + String project, String featurestoreId, String entityTypeId, String location, String endpoint) + throws IOException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + ListFeaturesRequest listFeaturesRequest = + ListFeaturesRequest.newBuilder() + .setParent( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .build(); + System.out.println("List Features Response"); + for (Feature element : + featurestoreServiceClient.listFeatures(listFeaturesRequest).iterateAll()) { + System.out.println(element); + } + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_list_features_sample] diff --git a/aiplatform/src/main/java/aiplatform/ListFeaturestoresAsyncSample.java b/aiplatform/src/main/java/aiplatform/ListFeaturestoresAsyncSample.java new file mode 100644 index 00000000000..16ce54f407e --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ListFeaturestoresAsyncSample.java @@ -0,0 +1,78 @@ +/* + * 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. + * + * + * List available featurestore details. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_list_featurestores_async_sample] + +import com.google.cloud.aiplatform.v1.Featurestore; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.ListFeaturestoresRequest; +import com.google.cloud.aiplatform.v1.ListFeaturestoresResponse; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.common.base.Strings; +import java.io.IOException; + +public class ListFeaturestoresAsyncSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + listFeaturestoresAsyncSample(project, location, endpoint); + } + + static void listFeaturestoresAsyncSample(String project, String location, String endpoint) + throws IOException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + ListFeaturestoresRequest listFeaturestoresRequest = + ListFeaturestoresRequest.newBuilder() + .setParent(LocationName.of(project, location).toString()) + .build(); + System.out.println("List Featurestores Async Response"); + while (true) { + ListFeaturestoresResponse listFeaturestoresResponse = + featurestoreServiceClient.listFeaturestoresCallable().call(listFeaturestoresRequest); + for (Featurestore element : listFeaturestoresResponse.getFeaturestoresList()) { + System.out.println(element); + } + String nextPageToken = listFeaturestoresResponse.getNextPageToken(); + if (!Strings.isNullOrEmpty(nextPageToken)) { + listFeaturestoresRequest = + listFeaturestoresRequest.toBuilder().setPageToken(nextPageToken).build(); + } else { + break; + } + } + } + } +} +// [END aiplatform_list_featurestores_async_sample] diff --git a/aiplatform/src/main/java/aiplatform/ListFeaturestoresSample.java b/aiplatform/src/main/java/aiplatform/ListFeaturestoresSample.java new file mode 100644 index 00000000000..db4e5d7aab5 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ListFeaturestoresSample.java @@ -0,0 +1,67 @@ +/* + * 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. + * + * + * List available featurestore details. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_list_featurestores_sample] + +import com.google.cloud.aiplatform.v1.Featurestore; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.ListFeaturestoresRequest; +import com.google.cloud.aiplatform.v1.LocationName; +import java.io.IOException; + +public class ListFeaturestoresSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + listFeaturestoresSample(project, location, endpoint); + } + + static void listFeaturestoresSample(String project, String location, String endpoint) + throws IOException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + ListFeaturestoresRequest listFeaturestoresRequest = + ListFeaturestoresRequest.newBuilder() + .setParent(LocationName.of(project, location).toString()) + .build(); + + System.out.println("List Featurestores Response"); + for (Featurestore element : + featurestoreServiceClient.listFeaturestores(listFeaturestoresRequest).iterateAll()) { + System.out.println(element); + } + } + } +} +// [END aiplatform_list_featurestores_sample] diff --git a/aiplatform/src/main/java/aiplatform/ListModelEvaluationSliceSample.java b/aiplatform/src/main/java/aiplatform/ListModelEvaluationSliceSample.java new file mode 100644 index 00000000000..09cf36e0a60 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/ListModelEvaluationSliceSample.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_list_model_evaluation_slice_sample] + +import com.google.cloud.aiplatform.v1.ModelEvaluationName; +import com.google.cloud.aiplatform.v1.ModelEvaluationSlice; +import com.google.cloud.aiplatform.v1.ModelEvaluationSlice.Slice; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import java.io.IOException; + +public class ListModelEvaluationSliceSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + // To obtain evaluationId run the code block below after setting modelServiceSettings. + // + // try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) + // { + // String location = "us-central1"; + // ModelName modelFullId = ModelName.of(project, location, modelId); + // ListModelEvaluationsRequest modelEvaluationsrequest = + // ListModelEvaluationsRequest.newBuilder().setParent(modelFullId.toString()).build(); + // for (ModelEvaluation modelEvaluation : + // modelServiceClient.listModelEvaluations(modelEvaluationsrequest).iterateAll()) { + // System.out.format("Model Evaluation Name: %s%n", modelEvaluation.getName()); + // } + // } + String project = "YOUR_PROJECT_ID"; + String modelId = "YOUR_MODEL_ID"; + String evaluationId = "YOUR_EVALUATION_ID"; + listModelEvaluationSliceSample(project, modelId, evaluationId); + } + + static void listModelEvaluationSliceSample(String project, String modelId, String evaluationId) + throws IOException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + ModelEvaluationName modelEvaluationName = + ModelEvaluationName.of(project, location, modelId, evaluationId); + + for (ModelEvaluationSlice modelEvaluationSlice : + modelServiceClient.listModelEvaluationSlices(modelEvaluationName).iterateAll()) { + System.out.format("Model Evaluation Slice Name: %s\n", modelEvaluationSlice.getName()); + System.out.format("Metrics Schema Uri: %s\n", modelEvaluationSlice.getMetricsSchemaUri()); + System.out.format("Metrics: %s\n", modelEvaluationSlice.getMetrics()); + System.out.format("Create Time: %s\n", modelEvaluationSlice.getCreateTime()); + + Slice slice = modelEvaluationSlice.getSlice(); + System.out.format("Slice Dimensions: %s\n", slice.getDimension()); + System.out.format("Slice Value: %s\n\n", slice.getValue()); + } + } + } +} +// [END aiplatform_list_model_evaluation_slice_sample] diff --git a/aiplatform/src/main/java/aiplatform/PredictCustomTrainedModelSample.java b/aiplatform/src/main/java/aiplatform/PredictCustomTrainedModelSample.java new file mode 100644 index 00000000000..40b2b2e8e5c --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/PredictCustomTrainedModelSample.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_predict_custom_trained_model_sample] + +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.PredictRequest; +import com.google.cloud.aiplatform.v1.PredictResponse; +import com.google.cloud.aiplatform.v1.PredictionServiceClient; +import com.google.cloud.aiplatform.v1.PredictionServiceSettings; +import com.google.protobuf.ListValue; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; +import java.util.List; + +public class PredictCustomTrainedModelSample { + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String instance = "[{ “feature_column_a”: “value”, “feature_column_b”: “value”}]"; + String project = "YOUR_PROJECT_ID"; + String endpointId = "YOUR_ENDPOINT_ID"; + predictCustomTrainedModel(project, endpointId, instance); + } + + static void predictCustomTrainedModel(String project, String endpointId, String instance) + throws IOException { + PredictionServiceSettings predictionServiceSettings = + PredictionServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PredictionServiceClient predictionServiceClient = + PredictionServiceClient.create(predictionServiceSettings)) { + String location = "us-central1"; + EndpointName endpointName = EndpointName.of(project, location, endpointId); + + ListValue.Builder listValue = ListValue.newBuilder(); + JsonFormat.parser().merge(instance, listValue); + List instanceList = listValue.getValuesList(); + + PredictRequest predictRequest = + PredictRequest.newBuilder() + .setEndpoint(endpointName.toString()) + .addAllInstances(instanceList) + .build(); + PredictResponse predictResponse = predictionServiceClient.predict(predictRequest); + + System.out.println("Predict Custom Trained model Response"); + System.out.format("\tDeployed Model Id: %s\n", predictResponse.getDeployedModelId()); + System.out.println("Predictions"); + for (Value prediction : predictResponse.getPredictionsList()) { + System.out.format("\tPrediction: %s\n", prediction); + } + } + } +} +// [END aiplatform_predict_custom_trained_model_sample] diff --git a/aiplatform/src/main/java/aiplatform/PredictImageClassificationSample.java b/aiplatform/src/main/java/aiplatform/PredictImageClassificationSample.java new file mode 100644 index 00000000000..c2d3ed60158 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/PredictImageClassificationSample.java @@ -0,0 +1,104 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_predict_image_classification_sample] + +import com.google.api.client.util.Base64; +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.PredictResponse; +import com.google.cloud.aiplatform.v1.PredictionServiceClient; +import com.google.cloud.aiplatform.v1.PredictionServiceSettings; +import com.google.cloud.aiplatform.v1.schema.predict.instance.ImageClassificationPredictionInstance; +import com.google.cloud.aiplatform.v1.schema.predict.params.ImageClassificationPredictionParams; +import com.google.cloud.aiplatform.v1.schema.predict.prediction.ClassificationPredictionResult; +import com.google.protobuf.Value; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class PredictImageClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String fileName = "YOUR_IMAGE_FILE_PATH"; + String endpointId = "YOUR_ENDPOINT_ID"; + predictImageClassification(project, fileName, endpointId); + } + + static void predictImageClassification(String project, String fileName, String endpointId) + throws IOException { + PredictionServiceSettings settings = + PredictionServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PredictionServiceClient predictionServiceClient = + PredictionServiceClient.create(settings)) { + String location = "us-central1"; + EndpointName endpointName = EndpointName.of(project, location, endpointId); + + byte[] contents = Base64.encodeBase64(Files.readAllBytes(Paths.get(fileName))); + String content = new String(contents, StandardCharsets.UTF_8); + + ImageClassificationPredictionInstance predictionInstance = + ImageClassificationPredictionInstance.newBuilder().setContent(content).build(); + + List instances = new ArrayList<>(); + instances.add(ValueConverter.toValue(predictionInstance)); + + ImageClassificationPredictionParams predictionParams = + ImageClassificationPredictionParams.newBuilder() + .setConfidenceThreshold((float) 0.5) + .setMaxPredictions(5) + .build(); + + PredictResponse predictResponse = + predictionServiceClient.predict( + endpointName, instances, ValueConverter.toValue(predictionParams)); + System.out.println("Predict Image Classification Response"); + System.out.format("\tDeployed Model Id: %s\n", predictResponse.getDeployedModelId()); + + System.out.println("Predictions"); + for (Value prediction : predictResponse.getPredictionsList()) { + + ClassificationPredictionResult.Builder resultBuilder = + ClassificationPredictionResult.newBuilder(); + // Display names and confidences values correspond to + // IDs in the ID list. + ClassificationPredictionResult result = + (ClassificationPredictionResult) ValueConverter.fromValue(resultBuilder, prediction); + int counter = 0; + for (Long id : result.getIdsList()) { + System.out.printf("Label ID: %d\n", id); + System.out.printf("Label: %s\n", result.getDisplayNames(counter)); + System.out.printf("Confidence: %.4f\n", result.getConfidences(counter)); + counter++; + } + } + } + } +} +// [END aiplatform_predict_image_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/PredictImageObjectDetectionSample.java b/aiplatform/src/main/java/aiplatform/PredictImageObjectDetectionSample.java new file mode 100644 index 00000000000..16e2ac60585 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/PredictImageObjectDetectionSample.java @@ -0,0 +1,103 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_predict_image_object_detection_sample] + +import com.google.api.client.util.Base64; +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.PredictResponse; +import com.google.cloud.aiplatform.v1.PredictionServiceClient; +import com.google.cloud.aiplatform.v1.PredictionServiceSettings; +import com.google.cloud.aiplatform.v1.schema.predict.instance.ImageObjectDetectionPredictionInstance; +import com.google.cloud.aiplatform.v1.schema.predict.params.ImageObjectDetectionPredictionParams; +import com.google.cloud.aiplatform.v1.schema.predict.prediction.ImageObjectDetectionPredictionResult; +import com.google.protobuf.Value; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; + +public class PredictImageObjectDetectionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String fileName = "YOUR_IMAGE_FILE_PATH"; + String endpointId = "YOUR_ENDPOINT_ID"; + predictImageObjectDetection(project, fileName, endpointId); + } + + static void predictImageObjectDetection(String project, String fileName, String endpointId) + throws IOException { + PredictionServiceSettings settings = + PredictionServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PredictionServiceClient predictionServiceClient = + PredictionServiceClient.create(settings)) { + String location = "us-central1"; + EndpointName endpointName = EndpointName.of(project, location, endpointId); + + byte[] contents = Base64.encodeBase64(Files.readAllBytes(Paths.get(fileName))); + String content = new String(contents, StandardCharsets.UTF_8); + + ImageObjectDetectionPredictionParams params = + ImageObjectDetectionPredictionParams.newBuilder() + .setConfidenceThreshold((float) (0.5)) + .setMaxPredictions(5) + .build(); + + ImageObjectDetectionPredictionInstance instance = + ImageObjectDetectionPredictionInstance.newBuilder().setContent(content).build(); + + List instances = new ArrayList<>(); + instances.add(ValueConverter.toValue(instance)); + + PredictResponse predictResponse = + predictionServiceClient.predict(endpointName, instances, ValueConverter.toValue(params)); + System.out.println("Predict Image Object Detection Response"); + System.out.format("\tDeployed Model Id: %s\n", predictResponse.getDeployedModelId()); + + System.out.println("Predictions"); + for (Value prediction : predictResponse.getPredictionsList()) { + + ImageObjectDetectionPredictionResult.Builder resultBuilder = + ImageObjectDetectionPredictionResult.newBuilder(); + + ImageObjectDetectionPredictionResult result = + (ImageObjectDetectionPredictionResult) + ValueConverter.fromValue(resultBuilder, prediction); + + for (int i = 0; i < result.getIdsCount(); i++) { + System.out.printf("\tDisplay name: %s\n", result.getDisplayNames(i)); + System.out.printf("\tConfidences: %f\n", result.getConfidences(i)); + System.out.printf("\tIDs: %d\n", result.getIds(i)); + System.out.printf("\tBounding boxes: %s\n", result.getBboxes(i)); + } + } + } + } +} +// [END aiplatform_predict_image_object_detection_sample] diff --git a/aiplatform/src/main/java/aiplatform/PredictTabularClassificationSample.java b/aiplatform/src/main/java/aiplatform/PredictTabularClassificationSample.java new file mode 100644 index 00000000000..59adf1885d6 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/PredictTabularClassificationSample.java @@ -0,0 +1,84 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_predict_tabular_classification_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.PredictResponse; +import com.google.cloud.aiplatform.v1.PredictionServiceClient; +import com.google.cloud.aiplatform.v1.PredictionServiceSettings; +import com.google.cloud.aiplatform.v1.schema.predict.prediction.TabularClassificationPredictionResult; +import com.google.protobuf.ListValue; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; +import java.util.List; + +public class PredictTabularClassificationSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String instance = "[{ “feature_column_a”: “value”, “feature_column_b”: “value”}]"; + String endpointId = "YOUR_ENDPOINT_ID"; + predictTabularClassification(instance, project, endpointId); + } + + static void predictTabularClassification(String instance, String project, String endpointId) + throws IOException { + PredictionServiceSettings predictionServiceSettings = + PredictionServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PredictionServiceClient predictionServiceClient = + PredictionServiceClient.create(predictionServiceSettings)) { + String location = "us-central1"; + EndpointName endpointName = EndpointName.of(project, location, endpointId); + + ListValue.Builder listValue = ListValue.newBuilder(); + JsonFormat.parser().merge(instance, listValue); + List instanceList = listValue.getValuesList(); + + Value parameters = Value.newBuilder().setListValue(listValue).build(); + PredictResponse predictResponse = + predictionServiceClient.predict(endpointName, instanceList, parameters); + System.out.println("Predict Tabular Classification Response"); + System.out.format("\tDeployed Model Id: %s\n", predictResponse.getDeployedModelId()); + + System.out.println("Predictions"); + for (Value prediction : predictResponse.getPredictionsList()) { + TabularClassificationPredictionResult.Builder resultBuilder = + TabularClassificationPredictionResult.newBuilder(); + TabularClassificationPredictionResult result = + (TabularClassificationPredictionResult) + ValueConverter.fromValue(resultBuilder, prediction); + + for (int i = 0; i < result.getClassesCount(); i++) { + System.out.printf("\tClass: %s", result.getClasses(i)); + System.out.printf("\tScore: %f", result.getScores(i)); + } + } + } + } +} +// [END aiplatform_predict_tabular_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/PredictTabularRegressionSample.java b/aiplatform/src/main/java/aiplatform/PredictTabularRegressionSample.java new file mode 100644 index 00000000000..9520c958783 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/PredictTabularRegressionSample.java @@ -0,0 +1,83 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_predict_tabular_regression_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.PredictResponse; +import com.google.cloud.aiplatform.v1.PredictionServiceClient; +import com.google.cloud.aiplatform.v1.PredictionServiceSettings; +import com.google.cloud.aiplatform.v1.schema.predict.prediction.TabularRegressionPredictionResult; +import com.google.protobuf.ListValue; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; +import java.util.List; + +public class PredictTabularRegressionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String instance = "[{ “feature_column_a”: “value”, “feature_column_b”: “value”}]"; + String endpointId = "YOUR_ENDPOINT_ID"; + predictTabularRegression(instance, project, endpointId); + } + + static void predictTabularRegression(String instance, String project, String endpointId) + throws IOException { + PredictionServiceSettings predictionServiceSettings = + PredictionServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PredictionServiceClient predictionServiceClient = + PredictionServiceClient.create(predictionServiceSettings)) { + String location = "us-central1"; + EndpointName endpointName = EndpointName.of(project, location, endpointId); + + ListValue.Builder listValue = ListValue.newBuilder(); + JsonFormat.parser().merge(instance, listValue); + List instanceList = listValue.getValuesList(); + + Value parameters = Value.newBuilder().setListValue(listValue).build(); + PredictResponse predictResponse = + predictionServiceClient.predict(endpointName, instanceList, parameters); + System.out.println("Predict Tabular Regression Response"); + System.out.format("\tDisplay Model Id: %s\n", predictResponse.getDeployedModelId()); + + System.out.println("Predictions"); + for (Value prediction : predictResponse.getPredictionsList()) { + TabularRegressionPredictionResult.Builder resultBuilder = + TabularRegressionPredictionResult.newBuilder(); + + TabularRegressionPredictionResult result = + (TabularRegressionPredictionResult) ValueConverter.fromValue(resultBuilder, prediction); + + System.out.printf("\tUpper bound: %f\n", result.getUpperBound()); + System.out.printf("\tLower bound: %f\n", result.getLowerBound()); + System.out.printf("\tValue: %f\n", result.getValue()); + } + } + } +} +// [END aiplatform_predict_tabular_regression_sample] diff --git a/aiplatform/src/main/java/aiplatform/PredictTextClassificationSingleLabelSample.java b/aiplatform/src/main/java/aiplatform/PredictTextClassificationSingleLabelSample.java new file mode 100644 index 00000000000..3b66819d2bc --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/PredictTextClassificationSingleLabelSample.java @@ -0,0 +1,90 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_predict_text_classification_sample] +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.PredictResponse; +import com.google.cloud.aiplatform.v1.PredictionServiceClient; +import com.google.cloud.aiplatform.v1.PredictionServiceSettings; +import com.google.cloud.aiplatform.v1.schema.predict.instance.TextClassificationPredictionInstance; +import com.google.cloud.aiplatform.v1.schema.predict.prediction.ClassificationPredictionResult; +import com.google.protobuf.Value; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class PredictTextClassificationSingleLabelSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String content = "YOUR_TEXT_CONTENT"; + String endpointId = "YOUR_ENDPOINT_ID"; + + predictTextClassificationSingleLabel(project, content, endpointId); + } + + static void predictTextClassificationSingleLabel( + String project, String content, String endpointId) throws IOException { + PredictionServiceSettings predictionServiceSettings = + PredictionServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PredictionServiceClient predictionServiceClient = + PredictionServiceClient.create(predictionServiceSettings)) { + String location = "us-central1"; + EndpointName endpointName = EndpointName.of(project, location, endpointId); + + TextClassificationPredictionInstance predictionInstance = + TextClassificationPredictionInstance.newBuilder().setContent(content).build(); + + List instances = new ArrayList<>(); + instances.add(ValueConverter.toValue(predictionInstance)); + + PredictResponse predictResponse = + predictionServiceClient.predict(endpointName, instances, ValueConverter.EMPTY_VALUE); + System.out.println("Predict Text Classification Response"); + System.out.format("\tDeployed Model Id: %s\n", predictResponse.getDeployedModelId()); + + System.out.println("Predictions:\n\n"); + for (Value prediction : predictResponse.getPredictionsList()) { + + ClassificationPredictionResult.Builder resultBuilder = + ClassificationPredictionResult.newBuilder(); + + // Display names and confidences values correspond to + // IDs in the ID list. + ClassificationPredictionResult result = + (ClassificationPredictionResult) ValueConverter.fromValue(resultBuilder, prediction); + int counter = 0; + for (Long id : result.getIdsList()) { + System.out.printf("Label ID: %d\n", id); + System.out.printf("Label: %s\n", result.getDisplayNames(counter)); + System.out.printf("Confidence: %.4f\n", result.getConfidences(counter)); + counter++; + } + } + } + } +} +// [END aiplatform_predict_text_classification_sample] diff --git a/aiplatform/src/main/java/aiplatform/PredictTextEntityExtractionSample.java b/aiplatform/src/main/java/aiplatform/PredictTextEntityExtractionSample.java new file mode 100644 index 00000000000..b7f10df4970 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/PredictTextEntityExtractionSample.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_predict_text_entity_extraction_sample] + +import com.google.cloud.aiplatform.util.ValueConverter; +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.PredictResponse; +import com.google.cloud.aiplatform.v1.PredictionServiceClient; +import com.google.cloud.aiplatform.v1.PredictionServiceSettings; +import com.google.cloud.aiplatform.v1.schema.predict.instance.TextExtractionPredictionInstance; +import com.google.cloud.aiplatform.v1.schema.predict.prediction.TextExtractionPredictionResult; +import com.google.protobuf.Value; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class PredictTextEntityExtractionSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String content = "YOUR_TEXT_CONTENT"; + String endpointId = "YOUR_ENDPOINT_ID"; + + predictTextEntityExtraction(project, content, endpointId); + } + + static void predictTextEntityExtraction(String project, String content, String endpointId) + throws IOException { + PredictionServiceSettings predictionServiceSettings = + PredictionServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PredictionServiceClient predictionServiceClient = + PredictionServiceClient.create(predictionServiceSettings)) { + String location = "us-central1"; + String jsonString = "{\"content\": \"" + content + "\"}"; + + EndpointName endpointName = EndpointName.of(project, location, endpointId); + + TextExtractionPredictionInstance instance = + TextExtractionPredictionInstance.newBuilder().setContent(content).build(); + + List instances = new ArrayList<>(); + instances.add(ValueConverter.toValue(instance)); + + PredictResponse predictResponse = + predictionServiceClient.predict(endpointName, instances, ValueConverter.EMPTY_VALUE); + System.out.println("Predict Text Entity Extraction Response"); + System.out.format("\tDeployed Model Id: %s\n", predictResponse.getDeployedModelId()); + + System.out.println("Predictions"); + for (Value prediction : predictResponse.getPredictionsList()) { + TextExtractionPredictionResult.Builder resultBuilder = + TextExtractionPredictionResult.newBuilder(); + + TextExtractionPredictionResult result = + (TextExtractionPredictionResult) ValueConverter.fromValue(resultBuilder, prediction); + + for (int i = 0; i < result.getIdsCount(); i++) { + long textStartOffset = result.getTextSegmentStartOffsets(i); + long textEndOffset = result.getTextSegmentEndOffsets(i); + String entity = content.substring((int) textStartOffset, (int) textEndOffset); + + System.out.format("\tEntity: %s\n", entity); + System.out.format("\tEntity type: %s\n", result.getDisplayNames(i)); + System.out.format("\tConfidences: %f\n", result.getConfidences(i)); + System.out.format("\tIDs: %d\n", result.getIds(i)); + } + } + } + } +} +// [END aiplatform_predict_text_entity_extraction_sample] diff --git a/aiplatform/src/main/java/aiplatform/PredictTextSentimentAnalysisSample.java b/aiplatform/src/main/java/aiplatform/PredictTextSentimentAnalysisSample.java new file mode 100644 index 00000000000..1d57a65dd7f --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/PredictTextSentimentAnalysisSample.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_predict_text_sentiment_analysis_sample] + +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.PredictResponse; +import com.google.cloud.aiplatform.v1.PredictionServiceClient; +import com.google.cloud.aiplatform.v1.PredictionServiceSettings; +import com.google.protobuf.Value; +import com.google.protobuf.util.JsonFormat; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +public class PredictTextSentimentAnalysisSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String content = "YOUR_TEXT_CONTENT"; + String endpointId = "YOUR_ENDPOINT_ID"; + + predictTextSentimentAnalysis(project, content, endpointId); + } + + static void predictTextSentimentAnalysis(String project, String content, String endpointId) + throws IOException { + PredictionServiceSettings predictionServiceSettings = + PredictionServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (PredictionServiceClient predictionServiceClient = + PredictionServiceClient.create(predictionServiceSettings)) { + String location = "us-central1"; + String jsonString = "{\"content\": \"" + content + "\"}"; + + EndpointName endpointName = EndpointName.of(project, location, endpointId); + + Value parameter = Value.newBuilder().setNumberValue(0).setNumberValue(5).build(); + Value.Builder instance = Value.newBuilder(); + JsonFormat.parser().merge(jsonString, instance); + + List instances = new ArrayList<>(); + instances.add(instance.build()); + + PredictResponse predictResponse = + predictionServiceClient.predict(endpointName, instances, parameter); + System.out.println("Predict Text Sentiment Analysis Response"); + System.out.format("\tDeployed Model Id: %s\n", predictResponse.getDeployedModelId()); + + System.out.println("Predictions"); + for (Value prediction : predictResponse.getPredictionsList()) { + System.out.format("\tPrediction: %s\n", prediction); + } + } + } +} +// [END aiplatform_predict_text_sentiment_analysis_sample] diff --git a/aiplatform/src/main/java/aiplatform/SearchFeaturesAsyncSample.java b/aiplatform/src/main/java/aiplatform/SearchFeaturesAsyncSample.java new file mode 100644 index 00000000000..595fe18c533 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/SearchFeaturesAsyncSample.java @@ -0,0 +1,81 @@ +/* + * 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. + * + * + * Search for featurestore resources. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_search_features_async_sample] + +import com.google.cloud.aiplatform.v1.Feature; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.SearchFeaturesRequest; +import com.google.cloud.aiplatform.v1.SearchFeaturesResponse; +import com.google.common.base.Strings; +import java.io.IOException; + +public class SearchFeaturesAsyncSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String query = "YOUR_QUERY"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + searchFeaturesAsyncSample(project, query, location, endpoint); + } + + static void searchFeaturesAsyncSample( + String project, String query, String location, String endpoint) throws IOException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + SearchFeaturesRequest searchFeaturesRequest = + SearchFeaturesRequest.newBuilder() + .setLocation(LocationName.of(project, location).toString()) + .setQuery(query) + .build(); + System.out.println("Search Features Async Response"); + while (true) { + SearchFeaturesResponse response = + featurestoreServiceClient.searchFeaturesCallable().call(searchFeaturesRequest); + for (Feature element : response.getFeaturesList()) { + System.out.println(element); + } + String nextPageToken = response.getNextPageToken(); + if (!Strings.isNullOrEmpty(nextPageToken)) { + searchFeaturesRequest = + searchFeaturesRequest.toBuilder().setPageToken(nextPageToken).build(); + } else { + break; + } + } + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_search_features_async_sample] diff --git a/aiplatform/src/main/java/aiplatform/SearchFeaturesSample.java b/aiplatform/src/main/java/aiplatform/SearchFeaturesSample.java new file mode 100644 index 00000000000..62309a5a99e --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/SearchFeaturesSample.java @@ -0,0 +1,69 @@ +/* + * 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. + * + * + * Search for featurestore resources. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_search_features_sample] + +import com.google.cloud.aiplatform.v1.Feature; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.SearchFeaturesRequest; +import java.io.IOException; + +public class SearchFeaturesSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String query = "YOUR_QUERY"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + searchFeaturesSample(project, query, location, endpoint); + } + + static void searchFeaturesSample(String project, String query, String location, String endpoint) + throws IOException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + SearchFeaturesRequest searchFeaturesRequest = + SearchFeaturesRequest.newBuilder() + .setLocation(LocationName.of(project, location).toString()) + .setQuery(query) + .build(); + System.out.println("Search Features Response"); + for (Feature element : + featurestoreServiceClient.searchFeatures(searchFeaturesRequest).iterateAll()) { + System.out.println(element); + } + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_search_features_sample] diff --git a/aiplatform/src/main/java/aiplatform/UndeployModelSample.java b/aiplatform/src/main/java/aiplatform/UndeployModelSample.java new file mode 100644 index 00000000000..db11f300166 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/UndeployModelSample.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_undeploy_model_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.EndpointName; +import com.google.cloud.aiplatform.v1.EndpointServiceClient; +import com.google.cloud.aiplatform.v1.EndpointServiceSettings; +import com.google.cloud.aiplatform.v1.ModelName; +import com.google.cloud.aiplatform.v1.UndeployModelOperationMetadata; +import com.google.cloud.aiplatform.v1.UndeployModelResponse; +import java.io.IOException; +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class UndeployModelSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String endpointId = "YOUR_ENDPOINT_ID"; + String modelId = "YOUR_MODEL_ID"; + undeployModelSample(project, endpointId, modelId); + } + + static void undeployModelSample(String project, String endpointId, String modelId) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + EndpointServiceSettings endpointServiceSettings = + EndpointServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (EndpointServiceClient endpointServiceClient = + EndpointServiceClient.create(endpointServiceSettings)) { + String location = "us-central1"; + EndpointName endpointName = EndpointName.of(project, location, endpointId); + ModelName modelName = ModelName.of(project, location, modelId); + + // key '0' assigns traffic for the newly deployed model + // Traffic percentage values must add up to 100 + // Leave dictionary empty if endpoint should not accept any traffic + Map trafficSplit = new HashMap<>(); + trafficSplit.put("0", 100); + + OperationFuture operation = + endpointServiceClient.undeployModelAsync( + endpointName.toString(), modelName.toString(), trafficSplit); + System.out.format("Operation name: %s\n", operation.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + UndeployModelResponse undeployModelResponse = operation.get(180, TimeUnit.SECONDS); + + System.out.format("Undeploy Model Response: %s\n", undeployModelResponse); + } + } +} +// [END aiplatform_undeploy_model_sample] diff --git a/aiplatform/src/main/java/aiplatform/UpdateEntityTypeMonitoringSample.java b/aiplatform/src/main/java/aiplatform/UpdateEntityTypeMonitoringSample.java new file mode 100644 index 00000000000..3133b146f8b --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/UpdateEntityTypeMonitoringSample.java @@ -0,0 +1,87 @@ +/* + * 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. + * + * + * Update entity type. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_update_entity_type_monitoring_sample] + +import com.google.cloud.aiplatform.v1.EntityType; +import com.google.cloud.aiplatform.v1.EntityTypeName; +import com.google.cloud.aiplatform.v1.FeaturestoreMonitoringConfig; +import com.google.cloud.aiplatform.v1.FeaturestoreMonitoringConfig.SnapshotAnalysis; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.UpdateEntityTypeRequest; +import java.io.IOException; + +public class UpdateEntityTypeMonitoringSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + int monitoringIntervalDays = 1; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + updateEntityTypeMonitoringSample( + project, featurestoreId, entityTypeId, monitoringIntervalDays, location, endpoint); + } + + static void updateEntityTypeMonitoringSample( + String project, + String featurestoreId, + String entityTypeId, + int monitoringIntervalDays, + String location, + String endpoint) + throws IOException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + FeaturestoreMonitoringConfig featurestoreMonitoringConfig = + FeaturestoreMonitoringConfig.newBuilder() + .setSnapshotAnalysis( + SnapshotAnalysis.newBuilder().setMonitoringIntervalDays(monitoringIntervalDays)) + .build(); + EntityType entityType = + EntityType.newBuilder() + .setName( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .setMonitoringConfig(featurestoreMonitoringConfig) + .build(); + + UpdateEntityTypeRequest updateEntityTypeRequest = + UpdateEntityTypeRequest.newBuilder().setEntityType(entityType).build(); + EntityType entityTypeResponse = + featurestoreServiceClient.updateEntityType(updateEntityTypeRequest); + System.out.println("Update Entity Type Monitoring Response"); + System.out.println(entityTypeResponse); + } + } +} +// [END aiplatform_update_entity_type_monitoring_sample] diff --git a/aiplatform/src/main/java/aiplatform/UpdateEntityTypeSample.java b/aiplatform/src/main/java/aiplatform/UpdateEntityTypeSample.java new file mode 100644 index 00000000000..bd7af265020 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/UpdateEntityTypeSample.java @@ -0,0 +1,80 @@ +/* + * 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. + * + * + * Update entity type. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_update_entity_type_sample] + +import com.google.cloud.aiplatform.v1.EntityType; +import com.google.cloud.aiplatform.v1.EntityTypeName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.UpdateEntityTypeRequest; +import java.io.IOException; + +public class UpdateEntityTypeSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String description = "Update Description"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + updateEntityTypeSample(project, featurestoreId, entityTypeId, description, location, endpoint); + } + + static void updateEntityTypeSample( + String project, + String featurestoreId, + String entityTypeId, + String description, + String location, + String endpoint) + throws IOException { + + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + EntityType entityType = + EntityType.newBuilder() + .setName( + EntityTypeName.of(project, location, featurestoreId, entityTypeId).toString()) + .setDescription(description) + .build(); + + UpdateEntityTypeRequest updateEntityTypeRequest = + UpdateEntityTypeRequest.newBuilder().setEntityType(entityType).build(); + EntityType entityTypeResponse = + featurestoreServiceClient.updateEntityType(updateEntityTypeRequest); + System.out.println("Update Entity Type Response"); + System.out.println(entityTypeResponse); + } + } +} +// [END aiplatform_update_entity_type_sample] diff --git a/aiplatform/src/main/java/aiplatform/UpdateFeatureSample.java b/aiplatform/src/main/java/aiplatform/UpdateFeatureSample.java new file mode 100644 index 00000000000..a68ada038ac --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/UpdateFeatureSample.java @@ -0,0 +1,79 @@ +/* + * 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. + * + * + * Update feature. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_update_feature_sample] + +import com.google.cloud.aiplatform.v1.Feature; +import com.google.cloud.aiplatform.v1.FeatureName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.UpdateFeatureRequest; +import java.io.IOException; + +public class UpdateFeatureSample { + + public static void main(String[] args) throws IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + String entityTypeId = "YOUR_ENTITY_TYPE_ID"; + String featureId = "YOUR_FEATURE_ID"; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + updateFeatureSample(project, featurestoreId, entityTypeId, featureId, location, endpoint); + } + + static void updateFeatureSample( + String project, + String featurestoreId, + String entityTypeId, + String featureId, + String location, + String endpoint) + throws IOException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + Feature feature = + Feature.newBuilder() + .setName( + FeatureName.of(project, location, featurestoreId, entityTypeId, featureId) + .toString()) + .setDescription("sample feature title updated") + .build(); + + UpdateFeatureRequest request = UpdateFeatureRequest.newBuilder().setFeature(feature).build(); + Feature featureResponse = featurestoreServiceClient.updateFeature(request); + System.out.println("Update Feature Response"); + System.out.format("Name: %s%n", featureResponse.getName()); + featurestoreServiceClient.close(); + } + } +} +// [END aiplatform_update_feature_sample] diff --git a/aiplatform/src/main/java/aiplatform/UpdateFeaturestoreFixedNodesSample.java b/aiplatform/src/main/java/aiplatform/UpdateFeaturestoreFixedNodesSample.java new file mode 100644 index 00000000000..71ef51edcc9 --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/UpdateFeaturestoreFixedNodesSample.java @@ -0,0 +1,93 @@ +/* + * 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. + * + * + * Update featurestore. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_update_featurestore_fixed_nodes_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.Featurestore; +import com.google.cloud.aiplatform.v1.Featurestore.OnlineServingConfig; +import com.google.cloud.aiplatform.v1.FeaturestoreName; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1.UpdateFeaturestoreOperationMetadata; +import com.google.cloud.aiplatform.v1.UpdateFeaturestoreRequest; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class UpdateFeaturestoreFixedNodesSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + int fixedNodeCount = 1; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 300; + updateFeaturestoreFixedNodesSample( + project, featurestoreId, fixedNodeCount, location, endpoint, timeout); + } + + static void updateFeaturestoreFixedNodesSample( + String project, + String featurestoreId, + int fixedNodeCount, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + OnlineServingConfig.Builder builderValue = + OnlineServingConfig.newBuilder().setFixedNodeCount(fixedNodeCount); + Featurestore featurestore = + Featurestore.newBuilder() + .setName(FeaturestoreName.of(project, location, featurestoreId).toString()) + .setOnlineServingConfig(builderValue) + .build(); + + UpdateFeaturestoreRequest request = + UpdateFeaturestoreRequest.newBuilder().setFeaturestore(featurestore).build(); + + OperationFuture updateFeaturestoreFuture = + featurestoreServiceClient.updateFeaturestoreAsync(request); + System.out.format( + "Operation name: %s%n", updateFeaturestoreFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Featurestore featurestoreResponse = updateFeaturestoreFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Update Featurestore Fixed Nodes Response"); + System.out.format("Name: %s%n", featurestoreResponse.getName()); + } + } +} +// [END aiplatform_update_featurestore_fixed_nodes_sample] diff --git a/aiplatform/src/main/java/aiplatform/UpdateFeaturestoreSample.java b/aiplatform/src/main/java/aiplatform/UpdateFeaturestoreSample.java new file mode 100644 index 00000000000..7ccb0b0a18e --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/UpdateFeaturestoreSample.java @@ -0,0 +1,98 @@ +/* + * 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. + * + * + * Updates the parameters of a single featurestore. See + * https://cloud.google.com/vertex-ai/docs/featurestore/setup before running + * the code snippet + */ + +package aiplatform; + +// [START aiplatform_update_featurestore_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1beta1.Featurestore; +import com.google.cloud.aiplatform.v1beta1.Featurestore.OnlineServingConfig; +import com.google.cloud.aiplatform.v1beta1.Featurestore.OnlineServingConfig.Scaling; +import com.google.cloud.aiplatform.v1beta1.FeaturestoreName; +import com.google.cloud.aiplatform.v1beta1.FeaturestoreServiceClient; +import com.google.cloud.aiplatform.v1beta1.FeaturestoreServiceSettings; +import com.google.cloud.aiplatform.v1beta1.UpdateFeaturestoreOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.UpdateFeaturestoreRequest; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class UpdateFeaturestoreSample { + + public static void main(String[] args) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String featurestoreId = "YOUR_FEATURESTORE_ID"; + int minNodeCount = 2; + int maxNodeCount = 4; + String location = "us-central1"; + String endpoint = "us-central1-aiplatform.googleapis.com:443"; + int timeout = 300; + updateFeaturestoreSample( + project, featurestoreId, minNodeCount, maxNodeCount, location, endpoint, timeout); + } + + static void updateFeaturestoreSample( + String project, + String featurestoreId, + int minNodeCount, + int maxNodeCount, + String location, + String endpoint, + int timeout) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + FeaturestoreServiceSettings featurestoreServiceSettings = + FeaturestoreServiceSettings.newBuilder().setEndpoint(endpoint).build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (FeaturestoreServiceClient featurestoreServiceClient = + FeaturestoreServiceClient.create(featurestoreServiceSettings)) { + + OnlineServingConfig.Builder builderValue = + OnlineServingConfig.newBuilder() + .setScaling( + Scaling.newBuilder().setMinNodeCount(minNodeCount).setMaxNodeCount(maxNodeCount)); + Featurestore featurestore = + Featurestore.newBuilder() + .setName(FeaturestoreName.of(project, location, featurestoreId).toString()) + .setOnlineServingConfig(builderValue) + .build(); + + UpdateFeaturestoreRequest request = + UpdateFeaturestoreRequest.newBuilder().setFeaturestore(featurestore).build(); + + OperationFuture updateFeaturestoreFuture = + featurestoreServiceClient.updateFeaturestoreAsync(request); + System.out.format( + "Operation name: %s%n", updateFeaturestoreFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + Featurestore featurestoreResponse = updateFeaturestoreFuture.get(timeout, TimeUnit.SECONDS); + System.out.println("Update Featurestore Response"); + System.out.format("Name: %s%n", featurestoreResponse.getName()); + } + } +} +// [END aiplatform_update_featurestore_sample] diff --git a/aiplatform/src/main/java/aiplatform/UploadModelSample.java b/aiplatform/src/main/java/aiplatform/UploadModelSample.java new file mode 100644 index 00000000000..f6b2fecec8a --- /dev/null +++ b/aiplatform/src/main/java/aiplatform/UploadModelSample.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package aiplatform; + +// [START aiplatform_upload_model_sample] + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1.LocationName; +import com.google.cloud.aiplatform.v1.Model; +import com.google.cloud.aiplatform.v1.ModelContainerSpec; +import com.google.cloud.aiplatform.v1.ModelServiceClient; +import com.google.cloud.aiplatform.v1.ModelServiceSettings; +import com.google.cloud.aiplatform.v1.UploadModelOperationMetadata; +import com.google.cloud.aiplatform.v1.UploadModelResponse; +import java.io.IOException; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +public class UploadModelSample { + public static void main(String[] args) + throws InterruptedException, ExecutionException, TimeoutException, IOException { + // TODO(developer): Replace these variables before running the sample. + String project = "YOUR_PROJECT_ID"; + String modelDisplayName = "YOUR_MODEL_DISPLAY_NAME"; + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/custom_task_1.0.0.yaml"; + String imageUri = "YOUR_IMAGE_URI"; + String artifactUri = "gs://your-gcs-bucket/artifact_path"; + uploadModel(project, modelDisplayName, metadataSchemaUri, imageUri, artifactUri); + } + + static void uploadModel( + String project, + String modelDisplayName, + String metadataSchemaUri, + String imageUri, + String artifactUri) + throws IOException, InterruptedException, ExecutionException, TimeoutException { + ModelServiceSettings modelServiceSettings = + ModelServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. After completing all of your requests, call + // the "close" method on the client to safely clean up any remaining background resources. + try (ModelServiceClient modelServiceClient = ModelServiceClient.create(modelServiceSettings)) { + String location = "us-central1"; + LocationName locationName = LocationName.of(project, location); + + ModelContainerSpec modelContainerSpec = + ModelContainerSpec.newBuilder().setImageUri(imageUri).build(); + + Model model = + Model.newBuilder() + .setDisplayName(modelDisplayName) + .setMetadataSchemaUri(metadataSchemaUri) + .setArtifactUri(artifactUri) + .setContainerSpec(modelContainerSpec) + .build(); + + OperationFuture uploadModelResponseFuture = + modelServiceClient.uploadModelAsync(locationName, model); + System.out.format( + "Operation name: %s\n", uploadModelResponseFuture.getInitialFuture().get().getName()); + System.out.println("Waiting for operation to finish..."); + UploadModelResponse uploadModelResponse = uploadModelResponseFuture.get(5, TimeUnit.MINUTES); + + System.out.println("Upload Model Response"); + System.out.format("Model: %s\n", uploadModelResponse.getModel()); + } + } +} +// [END aiplatform_upload_model_sample] diff --git a/aiplatform/src/test/java/aiplatform/CancelDataLabelingJobSampleTest.java b/aiplatform/src/test/java/aiplatform/CancelDataLabelingJobSampleTest.java new file mode 100644 index 00000000000..6ea3303aa68 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CancelDataLabelingJobSampleTest.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CancelDataLabelingJobSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = System.getenv("DATA_LABELING_DATASET_ID"); + private static final String INSTRUCTION_URI = + "gs://ucaip-sample-resources/images/datalabeling_instructions.pdf"; + private static final String INPUT_SCHEMA_URI = + "gs://google-cloud-aiplatform/schema/datalabelingjob/inputs/image_classification.yaml"; + private static final String ANNOTATION_SPEC = "daisy"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String dataLabelingJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("DATA_LABELING_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Delete the created data labeling + DeleteDataLabelingJobSample.deleteDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Data Labeling Job."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore + public void testCancelDataLabelingJob() throws IOException, InterruptedException { + // Act + String dataLabelingDisplayName = + String.format( + "temp_data_labeling_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDataLabelingJobSample.createDataLabelingJob( + PROJECT, + dataLabelingDisplayName, + DATASET_ID, + INSTRUCTION_URI, + INPUT_SCHEMA_URI, + ANNOTATION_SPEC); + + String got = bout.toString(); + dataLabelingJobId = got.split("Name: ")[1].split("dataLabelingJobs/")[1].split("\n")[0]; + + CancelDataLabelingJobSample.cancelDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled Data labeling job"); + TimeUnit.MINUTES.sleep(1); + } +} diff --git a/aiplatform/src/test/java/aiplatform/CancelTrainingPipelineSampleTest.java b/aiplatform/src/test/java/aiplatform/CancelTrainingPipelineSampleTest.java new file mode 100644 index 00000000000..a95073f9dc6 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CancelTrainingPipelineSampleTest.java @@ -0,0 +1,123 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CancelTrainingPipelineSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = System.getenv("TRAINING_PIPELINE_DATASET_ID"); + private static final String TRAINING_TASK_DEFINITION = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/" + + "automl_image_classification_1.0.0.yaml"; + private static String TRAINING_PIPELINE_ID = null; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, TRAINING_PIPELINE_ID); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void cancelTrainingPipeline() throws IOException, InterruptedException { + // Act + String trainingPipelineDisplayName = + String.format( + "temp_create_training_pipeline_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + String modelDisplayName = + String.format( + "temp_create_training_pipeline_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineSample.createTrainingPipelineSample( + PROJECT, + trainingPipelineDisplayName, + DATASET_ID, + TRAINING_TASK_DEFINITION, + modelDisplayName); + + // Assert + String createTrainingPipelineResponse = bout.toString(); + assertThat(createTrainingPipelineResponse).contains(DATASET_ID); + assertThat(createTrainingPipelineResponse).contains("Create Training Pipeline Response"); + TRAINING_PIPELINE_ID = + createTrainingPipelineResponse + .split("Name: ")[1] + .split("trainingPipelines/")[1] + .split("\n")[0]; + + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, TRAINING_PIPELINE_ID); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(1); + + // Get TrainingPipeline + GetTrainingPipelineSample.getTrainingPipeline(PROJECT, TRAINING_PIPELINE_ID); + String trainingPipelineResponse = bout.toString(); + assertThat(trainingPipelineResponse).contains("Message: CANCELED"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobBigquerySampleTest.java b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobBigquerySampleTest.java new file mode 100644 index 00000000000..25114e60731 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobBigquerySampleTest.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CreateBatchPredictionJobBigquerySampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = System.getenv("BATCH_PREDICTION_TABULAR_BQ_MODEL_ID"); + private static final String BIGQUERY_SOURCE_URI = + "bq://ucaip-sample-tests.table_test.all_bq_types"; + private static final String BIGQUERY_DESTINATION_OUTPUT_URI_PREFIX = "bq://ucaip-sample-tests"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String batchPredictionJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("BATCH_PREDICTION_TABULAR_BQ_MODEL_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + CancelBatchPredictionJobSample.cancelBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Batch Prediction Job"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Batch Prediction Job + DeleteBatchPredictionJobSample.deleteBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Batch"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateBatchPredictionJobBigquerySample() throws IOException { + // Act + String batchPredictionDisplayName = + String.format( + "batch_prediction_bigquery_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateBatchPredictionJobBigquerySample.createBatchPredictionJobBigquerySample( + PROJECT, + batchPredictionDisplayName, + MODEL_ID, + "bigquery", + BIGQUERY_SOURCE_URI, + "bigquery", + BIGQUERY_DESTINATION_OUTPUT_URI_PREFIX); + + // Assert + String got = bout.toString(); + assertThat(got).contains(batchPredictionDisplayName); + assertThat(got).contains("response:"); + batchPredictionJobId = got.split("Name: ")[1].split("batchPredictionJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobSampleTest.java new file mode 100644 index 00000000000..1def01b3ddc --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobSampleTest.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CreateBatchPredictionJobSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = System.getenv("BATCH_PREDICTION_MODEL_ID"); + private static final String GCS_SOURCE_URI = + "gs://ucaip-samples-test-output/inputs/icn_batch_prediction_input.jsonl"; + private static final String GCS_OUTPUT_URI = "gs://ucaip-samples-test-output/"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String batchPredictionJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("BATCH_PREDICTION_MODEL_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + CancelBatchPredictionJobSample.cancelBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Batch Prediction Job"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Batch Prediction Job + DeleteBatchPredictionJobSample.deleteBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Batch"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateBatchPredictionJobSample() throws IOException { + // Act + String batchPredictionDisplayName = + String.format( + "batch_prediction_bigquery_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateBatchPredictionJobSample.createBatchPredictionJobSample( + PROJECT, + batchPredictionDisplayName, + MODEL_ID, + "jsonl", + GCS_SOURCE_URI, + "jsonl", + GCS_OUTPUT_URI); + + // Assert + String got = bout.toString(); + assertThat(got).contains(batchPredictionDisplayName); + assertThat(got).contains("response:"); + batchPredictionJobId = got.split("Name: ")[1].split("batchPredictionJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextClassificationSampleTest.java new file mode 100644 index 00000000000..2d5d4d10baa --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextClassificationSampleTest.java @@ -0,0 +1,115 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateBatchPredictionJobTextClassificationSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String LOCATION = "us-central1"; + private static final String MODEL_ID = System.getenv("TEXT_CLASS_MODEL_ID"); + private static final String GCS_SOURCE_URI = + "gs://ucaip-samples-test-output/inputs/batch_predict_TCN/tcn_inputs.jsonl"; + private static final String GCS_OUTPUT_URI = "gs://ucaip-samples-test-output/"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String got; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TEXT_CLASS_MODEL_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + + String batchPredictionJobId = + got.split("name:")[1].split("batchPredictionJobs/")[1].split("\"\n")[0]; + + CancelBatchPredictionJobSample.cancelBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Batch Prediction Job"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Batch Prediction Job + DeleteBatchPredictionJobSample.deleteBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Batch"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateBatchPredictionJobTextClassificationSample() throws IOException { + // Act + String batchPredictionDisplayName = + String.format( + "temp_java_create_batch_prediction_TCN_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateBatchPredictionJobTextClassificationSample + .createBatchPredictionJobTextClassificationSample( + PROJECT, + LOCATION, + batchPredictionDisplayName, + MODEL_ID, + GCS_SOURCE_URI, + GCS_OUTPUT_URI); + + // Assert + got = bout.toString(); + assertThat(got).contains(batchPredictionDisplayName); + assertThat(got).contains("response:"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextEntityExtractionSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextEntityExtractionSampleTest.java new file mode 100644 index 00000000000..22b7a85dd8b --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextEntityExtractionSampleTest.java @@ -0,0 +1,113 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateBatchPredictionJobTextEntityExtractionSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String LOCATION = "us-central1"; + private static final String MODEL_ID = System.getenv("TEXT_ENTITY_MODEL_ID"); + private static final String GCS_SOURCE_URI = + "gs://ucaip-samples-test-output/inputs/batch_predict_TEN/ten_inputs.jsonl"; + private static final String GCS_OUTPUT_URI = "gs://ucaip-samples-test-output/"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String got; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TEXT_ENTITY_MODEL_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + String batchPredictionJobId = + got.split("name:")[1].split("batchPredictionJobs/")[1].split("\"\n")[0]; + CancelBatchPredictionJobSample.cancelBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Batch Prediction Job"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Batch Prediction Job + DeleteBatchPredictionJobSample.deleteBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Batch"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateBatchPredictionJobTextEntityExtractionSample() throws IOException { + // Act + String batchPredictionDisplayName = + String.format( + "temp_java_create_batch_prediction_TEN_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateBatchPredictionJobTextEntityExtractionSample + .createBatchPredictionJobTextEntityExtractionSample( + PROJECT, + LOCATION, + batchPredictionDisplayName, + MODEL_ID, + GCS_SOURCE_URI, + GCS_OUTPUT_URI); + + // Assert + got = bout.toString(); + assertThat(got).contains(batchPredictionDisplayName); + assertThat(got).contains("response:"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextSentimentAnalysisSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextSentimentAnalysisSampleTest.java new file mode 100644 index 00000000000..73b65b8fdb4 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobTextSentimentAnalysisSampleTest.java @@ -0,0 +1,113 @@ +/* + * Copyright 2021 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateBatchPredictionJobTextSentimentAnalysisSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String LOCATION = "us-central1"; + private static final String MODEL_ID = System.getenv("TEXT_SENTI_MODEL_ID"); + private static final String GCS_SOURCE_URI = + "gs://ucaip-samples-test-output/inputs/batch_predict_TSN/tsn_inputs.jsonl"; + private static final String GCS_OUTPUT_URI = "gs://ucaip-samples-test-output/"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String got; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TEXT_SENTI_MODEL_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + String batchPredictionJobId = + got.split("name:")[1].split("batchPredictionJobs/")[1].split("\"\n")[0]; + CancelBatchPredictionJobSample.cancelBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Batch Prediction Job"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Batch Prediction Job + DeleteBatchPredictionJobSample.deleteBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Batch"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateBatchPredictionJobTextSentimentAnalysisSample() throws IOException { + // Act + String batchPredictionDisplayName = + String.format( + "temp_java_create_batch_prediction_TSN_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateBatchPredictionJobTextSentimentAnalysisSample + .createBatchPredictionJobTextSentimentAnalysisSample( + PROJECT, + LOCATION, + batchPredictionDisplayName, + MODEL_ID, + GCS_SOURCE_URI, + GCS_OUTPUT_URI); + + // Assert + got = bout.toString(); + assertThat(got).contains(batchPredictionDisplayName); + assertThat(got).contains("response:"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoActionRecognitionSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoActionRecognitionSampleTest.java new file mode 100644 index 00000000000..90072c1c7ad --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoActionRecognitionSampleTest.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateBatchPredictionJobVideoActionRecognitionSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = + System.getenv("BATCH_PREDICTION_VIDEO_ACTION_RECOGNITION_MODEL_ID"); + private static final String GCS_SOURCE_URI = + "gs://ucaip-samples-test-output/inputs/icn_batch_prediction_input.jsonl"; + private static final String GCS_OUTPUT_URI = "gs://ucaip-samples-test-output/"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String batchPredictionJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("BATCH_PREDICTION_VIDEO_ACTION_RECOGNITION_MODEL_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + CancelBatchPredictionJobSample.cancelBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Batch Prediction Job"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Batch Prediction Job + DeleteBatchPredictionJobSample.deleteBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Batch"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateBatchPredictionJobVideoActionRecognitionSample() throws IOException { + // Act + String batchPredictionDisplayName = + String.format( + "batch_prediction_video_action_recognition_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateBatchPredictionJobVideoActionRecognitionSample + .createBatchPredictionJobVideoActionRecognitionSample( + PROJECT, batchPredictionDisplayName, MODEL_ID, GCS_SOURCE_URI, GCS_OUTPUT_URI); + + // Assert + String got = bout.toString(); + assertThat(got).contains(batchPredictionDisplayName); + assertThat(got).contains("response:"); + batchPredictionJobId = got.split("Name: ")[1].split("batchPredictionJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoClassificationSampleTest.java new file mode 100644 index 00000000000..1f64dbca4e0 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoClassificationSampleTest.java @@ -0,0 +1,111 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateBatchPredictionJobVideoClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = System.getenv("VIDEO_CLASS_MODEL_ID"); + private static final String GCS_SOURCE_URI = + "gs://ucaip-samples-test-output/inputs/vcn_40_batch_prediction_input.jsonl"; + private static final String GCS_DESTINATION_OUTPUT_URI_PREFIX = "gs://ucaip-samples-test-output/"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String batchPredictionJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("VIDEO_CLASS_MODEL_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Batch Prediction Job + CancelBatchPredictionJobSample.cancelBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Batch Prediction Job"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Batch Prediction Job + DeleteBatchPredictionJobSample.deleteBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Batch"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateBatchPredictionJobVideoClassificationSample() throws IOException { + // Act + String batchPredictionDisplayName = + String.format( + "batch_prediction_video_classification_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateBatchPredictionJobVideoClassificationSample.createBatchPredictionJobVideoClassification( + batchPredictionDisplayName, + MODEL_ID, + GCS_SOURCE_URI, + GCS_DESTINATION_OUTPUT_URI_PREFIX, + PROJECT); + + // Assert + String got = bout.toString(); + assertThat(got).contains(batchPredictionDisplayName); + assertThat(got).contains("Create Batch Prediction Job Video Classification Response"); + batchPredictionJobId = got.split("Name: ")[1].split("batchPredictionJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoObjectTrackingSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoObjectTrackingSampleTest.java new file mode 100644 index 00000000000..f4306e3d737 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateBatchPredictionJobVideoObjectTrackingSampleTest.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateBatchPredictionJobVideoObjectTrackingSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = System.getenv("VIDEO_OBJECT_DETECT_MODEL_ID"); + private static final String GCS_SOURCE_URI = + "gs://ucaip-samples-test-output/inputs/vot_batch_prediction_input.jsonl"; + private static final String GCS_DESTINATION_OUTPUT_URI_PREFIX = "gs://ucaip-samples-test-output/"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String batchPredictionJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Batch Prediction Job + CancelBatchPredictionJobSample.cancelBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Batch Prediction Job"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Batch Prediction Job + DeleteBatchPredictionJobSample.deleteBatchPredictionJobSample(PROJECT, batchPredictionJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Batch"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateBatchPredictionJobVideoObjectTrackingSample() throws IOException { + // Act + String batchPredictionDisplayName = + String.format( + "batch_prediction_video_object_tracking_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateBatchPredictionJobVideoObjectTrackingSample.batchPredictionJobVideoObjectTracking( + batchPredictionDisplayName, + MODEL_ID, + GCS_SOURCE_URI, + GCS_DESTINATION_OUTPUT_URI_PREFIX, + PROJECT); + + // Assert + String got = bout.toString(); + assertThat(got).contains(batchPredictionDisplayName); + assertThat(got).contains("Create Batch Prediction Job Video Object Tracking Response"); + batchPredictionJobId = got.split("Name: ")[1].split("batchPredictionJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobActiveLearningSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobActiveLearningSampleTest.java new file mode 100644 index 00000000000..5280476f333 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobActiveLearningSampleTest.java @@ -0,0 +1,115 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateDataLabelingJobActiveLearningSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = + System.getenv("DATA_LABELING_ACTIVE_LEARNING_DATASET_ID"); + private static final String INSTRUCTION_URI = + "gs://ucaip-sample-resources/images/datalabeling_instructions.pdf"; + private static final String INPUTS_SCHEMA_URI = + "gs://google-cloud-aiplatform/schema/datalabelingjob/inputs/image_classification_1.0.0.yaml"; + private static final String ANNOTATION_SPEC = "roses"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String dataLabelingJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("DATA_LABELING_ACTIVE_LEARNING_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel data labeling job + CancelDataLabelingJobSample.cancelDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled Data labeling job"); + TimeUnit.MINUTES.sleep(1); + + // Delete the created dataset + DeleteDataLabelingJobSample.deleteDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Data Labeling Job."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("Avoid creating actual data labeling job for humans") + public void testCreateDataLabelingJobActiveLearningSample() throws IOException { + // Act + String dataLabelingDisplayName = + String.format( + "temp_data_labeling_job_active_learning_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDataLabelingJobActiveLearningSample.createDataLabelingJobActiveLearningSample( + PROJECT, + dataLabelingDisplayName, + DATASET_ID, + INSTRUCTION_URI, + INPUTS_SCHEMA_URI, + ANNOTATION_SPEC); + + // Assert + String got = bout.toString(); + assertThat(got).contains(dataLabelingDisplayName); + assertThat(got).contains("Create Data Labeling Job Image Response"); + dataLabelingJobId = got.split("Name: ")[1].split("dataLabelingJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobImageSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobImageSampleTest.java new file mode 100644 index 00000000000..27dc9164002 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobImageSampleTest.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateDataLabelingJobImageSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = System.getenv("DATA_LABELING_IMAGE_DATASET_ID"); + private static final String INSTRUCTION_URI = + "gs://ucaip-sample-resources/images/datalabeling_instructions.pdf"; + private static final String ANNOTATION_SPEC = "roses"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String dataLabelingJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("DATA_LABELING_IMAGE_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel data labeling job + CancelDataLabelingJobSample.cancelDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled Data labeling job"); + TimeUnit.MINUTES.sleep(1); + + // Delete the created dataset + DeleteDataLabelingJobSample.deleteDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Data Labeling Job."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore + public void testCreateDataLabelingJobImageSample() throws IOException { + // Act + String dataLabelingDisplayName = + String.format( + "temp_data_labeling_job_image_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDataLabelingJobImageSample.createDataLabelingJobImage( + PROJECT, dataLabelingDisplayName, DATASET_ID, INSTRUCTION_URI, ANNOTATION_SPEC); + + // Assert + String got = bout.toString(); + assertThat(got).contains(dataLabelingDisplayName); + assertThat(got).contains("Create Data Labeling Job Image Response"); + dataLabelingJobId = got.split("Name: ")[1].split("dataLabelingJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobSampleTest.java new file mode 100644 index 00000000000..6f939353040 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobSampleTest.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateDataLabelingJobSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = System.getenv("DATA_LABELING_DATASET_ID"); + private static final String INSTRUCTION_URI = + "gs://ucaip-sample-resources/images/datalabeling_instructions.pdf"; + private static final String INPUT_SCHEMA_URI = + "gs://google-cloud-aiplatform/schema/datalabelingjob/inputs/image_classification.yaml"; + private static final String ANNOTATION_SPEC = "daisy"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String dataLabelingJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("DATA_LABELING_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel data labeling job + CancelDataLabelingJobSample.cancelDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled Data labeling job"); + TimeUnit.MINUTES.sleep(1); + + // Delete the created dataset + DeleteDataLabelingJobSample.deleteDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Data Labeling Job."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore + public void testCreateDataLabelingJobSample() throws IOException { + // Act + String dataLabelingDisplayName = + String.format( + "temp_data_labeling_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDataLabelingJobSample.createDataLabelingJob( + PROJECT, + dataLabelingDisplayName, + DATASET_ID, + INSTRUCTION_URI, + INPUT_SCHEMA_URI, + ANNOTATION_SPEC); + + // Assert + String got = bout.toString(); + assertThat(got).contains(dataLabelingDisplayName); + assertThat(got).contains("Create Data Labeling Job Response"); + dataLabelingJobId = got.split("Name: ")[1].split("dataLabelingJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobSpecialistPoolSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobSpecialistPoolSampleTest.java new file mode 100644 index 00000000000..7c41c5d844a --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobSpecialistPoolSampleTest.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateDataLabelingJobSpecialistPoolSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = + System.getenv("DATA_LABELING_ACTIVE_LEARNING_DATASET_ID"); + private static final String SPECIALIST_POOL_ID = + System.getenv("DATA_LABELING_SPECIALIST_POOL_ID"); + private static final String INSTRUCTION_URI = + "gs://ucaip-sample-resources/images/datalabeling_instructions.pdf"; + private static final String INPUTS_SCHEMA_URI = + "gs://google-cloud-aiplatform/schema/datalabelingjob/inputs/image_classification_1.0.0.yaml"; + private static final String ANNOTATION_SPEC = "roses"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String dataLabelingJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("DATA_LABELING_ACTIVE_LEARNING_DATASET_ID"); + requireEnvVar("DATA_LABELING_SPECIALIST_POOL_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel data labeling job + CancelDataLabelingJobSample.cancelDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled Data labeling job"); + TimeUnit.MINUTES.sleep(1); + + // Delete the created dataset + DeleteDataLabelingJobSample.deleteDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Data Labeling Job."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("Avoid creating actual data labeling job for humans") + public void testCreateDataLabelingJobSpecialistPoolSample() throws IOException { + // Act + String dataLabelingDisplayName = + String.format( + "temp_data_labeling_job_specialist_pool_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDataLabelingJobSpecialistPoolSample.createDataLabelingJobSpecialistPoolSample( + PROJECT, + dataLabelingDisplayName, + DATASET_ID, + SPECIALIST_POOL_ID, + INSTRUCTION_URI, + INPUTS_SCHEMA_URI, + ANNOTATION_SPEC); + + // Assert + String got = bout.toString(); + assertThat(got).contains(dataLabelingDisplayName); + assertThat(got).contains("Create Data Labeling Job Image Response"); + dataLabelingJobId = got.split("Name: ")[1].split("dataLabelingJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobVideoSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobVideoSampleTest.java new file mode 100644 index 00000000000..2c6ee822278 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDataLabelingJobVideoSampleTest.java @@ -0,0 +1,107 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateDataLabelingJobVideoSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = System.getenv("DATA_LABELING_VIDEO_DATASET_ID"); + private static final String INSTRUCTION_URI = + "gs://ucaip-sample-resources/images/datalabeling_instructions.pdf"; + private static final String ANNOTATION_SPEC = "cars"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String dataLabelingJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("DATA_LABELING_VIDEO_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel data labeling job + CancelDataLabelingJobSample.cancelDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled Data labeling job"); + TimeUnit.MINUTES.sleep(1); + + // Delete the created dataset + DeleteDataLabelingJobSample.deleteDataLabelingJob(PROJECT, dataLabelingJobId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Data Labeling Job."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("Avoid creating actual data labeling job for humans") + public void testCreateDataLabelingJobVideoSample() throws IOException { + // Act + String dataLabelingDisplayName = + String.format( + "temp_data_labeling_job_video_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDataLabelingJobVideoSample.createDataLabelingJobVideo( + PROJECT, dataLabelingDisplayName, DATASET_ID, INSTRUCTION_URI, ANNOTATION_SPEC); + + // Assert + String got = bout.toString(); + assertThat(got).contains(dataLabelingDisplayName); + assertThat(got).contains("Create Data Labeling Job Video Response"); + dataLabelingJobId = got.split("Name: ")[1].split("dataLabelingJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDatasetImageSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDatasetImageSampleTest.java new file mode 100644 index 00000000000..d4667e6111c --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDatasetImageSampleTest.java @@ -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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateDatasetImageSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String datasetId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Delete the created dataset + DeleteDatasetSample.deleteDatasetSample(PROJECT, datasetId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Dataset"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateDatasetSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + String datasetDisplayName = + String.format( + "temp_create_dataset_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDatasetImageSample.createDatasetImageSample(PROJECT, datasetDisplayName); + + // Assert + String got = bout.toString(); + assertThat(got).contains(datasetDisplayName); + assertThat(got).contains("Create Image Dataset Response"); + datasetId = got.split("Name: ")[1].split("datasets/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDatasetSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDatasetSampleTest.java new file mode 100644 index 00000000000..408bead923d --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDatasetSampleTest.java @@ -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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateDatasetSampleTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final String METADATA_SCHEMA_URI = + "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String datasetId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Delete the created dataset + DeleteDatasetSample.deleteDatasetSample(PROJECT_ID, datasetId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Dataset."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateDatasetSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + String displayName = + String.format( + "temp_create_dataset_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDatasetSample.createDatasetSample(PROJECT_ID, displayName, METADATA_SCHEMA_URI); + + // Assert + String got = bout.toString(); + assertThat(got).contains(displayName); + assertThat(got).contains("Create Dataset Response"); + datasetId = got.split("Name: ")[1].split("datasets/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDatasetTabularBigquerySampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDatasetTabularBigquerySampleTest.java new file mode 100644 index 00000000000..42b002514a5 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDatasetTabularBigquerySampleTest.java @@ -0,0 +1,93 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CreateDatasetTabularBigquerySampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String GCS_SOURCE_URI = "bq://ucaip-sample-tests.table_test.all_bq_types"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String datasetId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Delete the created dataset + DeleteDatasetSample.deleteDatasetSample(PROJECT, datasetId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Dataset."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateDatasetTabularBigquerySample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + String datasetDisplayName = + String.format( + "temp_create_dataset_table_bigquery_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDatasetTabularBigquerySample.createDatasetTableBigquery( + PROJECT, datasetDisplayName, GCS_SOURCE_URI); + + // Assert + String got = bout.toString(); + assertThat(got).contains(datasetDisplayName); + assertThat(got).contains("Create Dataset Table Bigquery sample"); + datasetId = got.split("Name: ")[1].split("datasets/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDatasetTabularGcsSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDatasetTabularGcsSampleTest.java new file mode 100644 index 00000000000..3d9c5bba225 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDatasetTabularGcsSampleTest.java @@ -0,0 +1,95 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateDatasetTabularGcsSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String GCS_SOURCE_URI = "gs://cloud-ml-tables-data/bank-marketing.csv"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String datasetId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Delete the created dataset + DeleteDatasetSample.deleteDatasetSample(PROJECT, datasetId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Dataset."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateDatasetTabularGcsSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + String datasetDisplayName = + String.format( + "temp_create_dataset_table_gcs_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDatasetTabularGcsSample.createDatasetTableGcs( + PROJECT, datasetDisplayName, GCS_SOURCE_URI); + + // Assert + String got = bout.toString(); + assertThat(got).contains(datasetDisplayName); + assertThat(got).contains("Create Dataset Table GCS sample"); + datasetId = got.split("Name: ")[1].split("datasets/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDatasetTextSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDatasetTextSampleTest.java new file mode 100644 index 00000000000..ba3c98df9ab --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDatasetTextSampleTest.java @@ -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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateDatasetTextSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String datasetId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Delete the created dataset + DeleteDatasetSample.deleteDatasetSample(PROJECT, datasetId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Dataset."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateDatasetSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + String datasetDisplayName = + String.format( + "temp_create_dataset_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDatasetTextSample.createDatasetTextSample(PROJECT, datasetDisplayName); + + // Assert + String got = bout.toString(); + assertThat(got).contains(datasetDisplayName); + assertThat(got).contains("Create Text Dataset Response"); + datasetId = got.split("Name: ")[1].split("datasets/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateDatasetVideoSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateDatasetVideoSampleTest.java new file mode 100644 index 00000000000..a983f079224 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateDatasetVideoSampleTest.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateDatasetVideoSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private String datasetId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Delete the created dataset + DeleteDatasetSample.deleteDatasetSample(PROJECT, datasetId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Dataset"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateDatasetVideoSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + String displayName = + String.format( + "temp_create_dataset_video_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateDatasetVideoSample.createDatasetSample(displayName, PROJECT); + + // Assert + String got = bout.toString(); + assertThat(got).contains(displayName); + assertThat(got).contains("Create Dataset Video Response"); + datasetId = got.split("Name: ")[1].split("datasets/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateEndpointSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateEndpointSampleTest.java new file mode 100644 index 00000000000..f301710da38 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateEndpointSampleTest.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateEndpointSampleTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String endpointId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Delete the created endpoint + DeleteEndpointSample.deleteEndpointSample(PROJECT_ID, endpointId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Delete Endpoint Response: "); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateEndpointSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + String displayName = + String.format( + "temp_create_endpoint_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateEndpointSample.createEndpointSample(PROJECT_ID, displayName); + + // Assert + String got = bout.toString(); + assertThat(got).contains("us-central1"); + assertThat(got).contains("Create Endpoint Response"); + endpointId = got.split("Name: ")[1].split("endpoints/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateHyperparameterTuningJobPythonPackageSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateHyperparameterTuningJobPythonPackageSampleTest.java new file mode 100644 index 00000000000..93f04e9e065 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateHyperparameterTuningJobPythonPackageSampleTest.java @@ -0,0 +1,118 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import com.google.cloud.aiplatform.v1beta1.JobServiceClient; +import com.google.cloud.aiplatform.v1beta1.JobServiceSettings; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateHyperparameterTuningJobPythonPackageSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String EXECUTOR_IMAGE_URI = + "us.gcr.io/cloud-aiplatform/training/tf-gpu.2-1:latest"; + private static final String PACKAGE_URI = + "gs://cloud-samples-data-us-central1/ai-platform-unified/training/python-packages/" + + "trainer.tar.bz2"; + private static final String PYTHON_MODULE = "trainer.hptuning_trainer"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String hyperparameterJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + try (JobServiceClient client = JobServiceClient.create(settings)) { + // Cancel hyper parameter job + String hyperparameterJobName = + String.format( + "projects/%s/locations/us-central1/hyperparameterTuningJobs/%s", + PROJECT, hyperparameterJobId); + client.cancelHyperparameterTuningJob(hyperparameterJobName); + + TimeUnit.MINUTES.sleep(1); + + // Delete the created job + client.deleteHyperparameterTuningJobAsync(hyperparameterJobName); + System.out.flush(); + System.setOut(originalPrintStream); + } + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateHyperparameterTuningJobPythonPackageSample() throws IOException { + String hyperparameterTuningJobDisplayName = + String.format( + "temp_hyperparameter_tuning_job_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + CreateHyperparameterTuningJobPythonPackageSample + .createHyperparameterTuningJobPythonPackageSample( + PROJECT, + hyperparameterTuningJobDisplayName, + EXECUTOR_IMAGE_URI, + PACKAGE_URI, + PYTHON_MODULE); + + // Assert + String got = bout.toString(); + assertThat(got).contains(hyperparameterTuningJobDisplayName); + assertThat(got).contains("response:"); + hyperparameterJobId = + got.split("Name: ")[1].split("hyperparameterTuningJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateHyperparameterTuningJobSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateHyperparameterTuningJobSampleTest.java new file mode 100644 index 00000000000..48343412a6f --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateHyperparameterTuningJobSampleTest.java @@ -0,0 +1,106 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import com.google.cloud.aiplatform.v1beta1.JobServiceClient; +import com.google.cloud.aiplatform.v1beta1.JobServiceSettings; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CreateHyperparameterTuningJobSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String CONTAINER_IMAGE_URI = + "gcr.io/ucaip-sample-tests/ucaip-training-test:latest"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String hyperparameterJobId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + JobServiceSettings settings = + JobServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + try (JobServiceClient client = JobServiceClient.create(settings)) { + // Cancel hyper parameter job + String hyperparameterJobName = + String.format( + "projects/%s/locations/us-central1/hyperparameterTuningJobs/%s", + PROJECT, hyperparameterJobId); + client.cancelHyperparameterTuningJob(hyperparameterJobName); + + TimeUnit.MINUTES.sleep(1); + + // Delete the created job + client.deleteHyperparameterTuningJobAsync(hyperparameterJobName); + System.out.flush(); + System.setOut(originalPrintStream); + } + } + + @Test + public void testCreateHyperparameterTuningJobSample() throws IOException { + String hyperparameterTuningJobDisplayName = + String.format( + "temp_hyperparameter_tuning_job_display_name_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateHyperparameterTuningJobSample.createHyperparameterTuningJobSample( + PROJECT, hyperparameterTuningJobDisplayName, CONTAINER_IMAGE_URI); + + String got = bout.toString(); + assertThat(got).contains(hyperparameterTuningJobDisplayName); + assertThat(got).contains("response:"); + hyperparameterJobId = + got.split("Name: ")[1].split("hyperparameterTuningJobs/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineCustomJobSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineCustomJobSampleTest.java new file mode 100644 index 00000000000..3762eb6bb33 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineCustomJobSampleTest.java @@ -0,0 +1,128 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import io.grpc.StatusRuntimeException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CreateTrainingPipelineCustomJobSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String CONTAINER_IMAGE_URI = + "gcr.io/ucaip-sample-tests/mnist-custom-job:latest"; + private static final String GCS_OUTPUT_DIRECTORY = + "gs://ucaip-samples-us-central1/training_pipeline_output"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + int retryCount = 3; + while (retryCount > 0) { + retryCount--; + try { + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + // if delete operation is successful, break out of the loop and continue + break; + } catch (StatusRuntimeException | ExecutionException ex) { + // wait for another 1 minute, then retry + System.out.println("Retrying (due to unfinished cancellation operation)..."); + TimeUnit.MINUTES.sleep(1); + } catch (Exception otherExceptions) { + // other exception, let them throw + throw otherExceptions; + } + } + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateTrainingPipelineCustomJobSample() throws IOException { + // Act + String trainingPipelineDisplayName = + String.format( + "temp_create_training_pipeline_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + String modelDisplayName = + String.format( + "temp_create_training_pipeline_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineCustomJobSample.createTrainingPipelineCustomJobSample( + PROJECT, + trainingPipelineDisplayName, + modelDisplayName, + CONTAINER_IMAGE_URI, + GCS_OUTPUT_DIRECTORY); + + // Assert + String got = bout.toString(); + assertThat(got).contains(trainingPipelineDisplayName); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineCustomTrainingManagedDatasetSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineCustomTrainingManagedDatasetSampleTest.java new file mode 100644 index 00000000000..11cb9b8f1cd --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineCustomTrainingManagedDatasetSampleTest.java @@ -0,0 +1,121 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CreateTrainingPipelineCustomTrainingManagedDatasetSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = System.getenv("CUSTOM_MANAGED_DATASET"); + private static final String ANNOTATION_SCHEMA_URI = + "gs://google-cloud-aiplatform/schema/dataset/annotation/image_classification_1.0.0.yaml"; + private static final String TRAINING_CONTAINER_IMAGE_URI = + "gcr.io/ucaip-sample-tests/custom-container-managed-dataset:latest"; + private static final String MODEL_CONTAIN_SPEC_IMAGE_URI = + "gcr.io/cloud-aiplatform/prediction/tf-gpu.1-15:latest"; + private static final String GCS_OUTPUT_DIRECTORY = + "gs://ucaip-samples-us-central1/training_pipeline_output/custom_training_managed_dataset"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("CUSTOM_MANAGED_DATASET"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateTrainingPipelineCustomTrainingManagedDatasetSample() throws IOException { + // Act + String trainingPipelineDisplayName = + String.format( + "temp_create_training_pipeline_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + String modelDisplayName = + String.format( + "temp_create_training_pipeline_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineCustomTrainingManagedDatasetSample + .createTrainingPipelineCustomTrainingManagedDatasetSample( + PROJECT, + trainingPipelineDisplayName, + modelDisplayName, + DATASET_ID, + ANNOTATION_SCHEMA_URI, + TRAINING_CONTAINER_IMAGE_URI, + MODEL_CONTAIN_SPEC_IMAGE_URI, + GCS_OUTPUT_DIRECTORY); + + // Assert + String got = bout.toString(); + assertThat(got).contains(trainingPipelineDisplayName); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineImageClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineImageClassificationSampleTest.java new file mode 100644 index 00000000000..e77cf0e2873 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineImageClassificationSampleTest.java @@ -0,0 +1,113 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateTrainingPipelineImageClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = + System.getenv("TRAINING_PIPELINE_IMAGE_CLASS_DATASET_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_IMAGE_CLASS_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateTrainingPipelineImageClassificationSample() throws IOException { + // Act + String trainingPipelineDisplayName = + String.format( + "temp_create_training_pipeline_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + String modelDisplayName = + String.format( + "temp_create_training_pipeline_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineImageClassificationSample.createTrainingPipelineImageClassificationSample( + PROJECT, trainingPipelineDisplayName, DATASET_ID, modelDisplayName); + + // Assert + String got = bout.toString(); + assertThat(got).contains(DATASET_ID); + assertThat(got).contains("Create Training Pipeline Image Classification Response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineImageObjectDetectionSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineImageObjectDetectionSampleTest.java new file mode 100644 index 00000000000..c4295cb9440 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineImageObjectDetectionSampleTest.java @@ -0,0 +1,109 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateTrainingPipelineImageObjectDetectionSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = + System.getenv("TRAINING_PIPELINE_IMAGE_OBJECT_DETECT_DATASET_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_IMAGE_OBJECT_DETECT_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateTrainingPipelineImageObjectDetectionSample() throws IOException { + String tempUuid = UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26); + // Act + String trainingPipelineDisplayName = + String.format("temp_create_training_pipeline_test_%s", tempUuid); + + String modelDisplayName = + String.format("temp_create_training_pipeline_model_test_%s", tempUuid); + + CreateTrainingPipelineImageObjectDetectionSample + .createTrainingPipelineImageObjectDetectionSample( + PROJECT, trainingPipelineDisplayName, DATASET_ID, modelDisplayName); + + // Assert + String got = bout.toString(); + assertThat(got).contains(DATASET_ID); + assertThat(got).contains("Create Training Pipeline Image Object Detection Response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineSampleTest.java new file mode 100644 index 00000000000..fe31cb03fa2 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineSampleTest.java @@ -0,0 +1,113 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateTrainingPipelineSampleTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = "1084241610289446912"; + private static final String TRAINING_TASK_DEFINITION = + "gs://google-cloud-aiplatform/schema/trainingjob/definition/" + + "automl_image_classification_1.0.0.yaml"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT_ID, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT_ID, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateTrainingPipelineSample() + throws IOException, InterruptedException, ExecutionException { + // Act + String tempUuid = UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26); + String trainingPipelineDisplayName = + String.format("temp_create_training_pipeline_test_%s", tempUuid); + + String modelDisplayName = + String.format("temp_create_training_pipeline_model_test_%s", tempUuid); + + CreateTrainingPipelineSample.createTrainingPipelineSample( + PROJECT_ID, + trainingPipelineDisplayName, + DATASET_ID, + TRAINING_TASK_DEFINITION, + modelDisplayName); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Create Training Pipeline Response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTabularClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTabularClassificationSampleTest.java new file mode 100644 index 00000000000..50ba9a264a3 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTabularClassificationSampleTest.java @@ -0,0 +1,126 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import com.google.cloud.aiplatform.v1.PipelineServiceClient; +import com.google.cloud.aiplatform.v1.PipelineServiceSettings; +import com.google.cloud.aiplatform.v1.TrainingPipeline; +import com.google.cloud.aiplatform.v1.TrainingPipelineName; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CreateTrainingPipelineTabularClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = + System.getenv("TRAINING_PIPELINE_TABLES_CLASSIFICATION_DATASET_ID"); + private static final String TARGET_COLUMN = "species"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_TABLES_CLASSIFICATION_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + + PipelineServiceSettings pipelineServiceSettings = + PipelineServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + try (PipelineServiceClient pipelineServiceClient = + PipelineServiceClient.create(pipelineServiceSettings)) { + String location = "us-central1"; + TrainingPipelineName trainingPipelineName = + TrainingPipelineName.of(PROJECT, location, trainingPipelineId); + + TrainingPipeline trainingPipelineResponse = + pipelineServiceClient.getTrainingPipeline(trainingPipelineName); + while (!trainingPipelineResponse.getState().name().contains("STATE_CANCELLED")) { + TimeUnit.SECONDS.sleep(30); + trainingPipelineResponse = pipelineServiceClient.getTrainingPipeline(trainingPipelineName); + } + } + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void createTrainingPipelineTabularClassification() throws IOException { + // Act + String modelDisplayName = + String.format( + "temp_create_training_pipelinetabularclassification_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineTabularClassificationSample.createTrainingPipelineTableClassification( + PROJECT, modelDisplayName, DATASET_ID, TARGET_COLUMN); + + // Assert + String got = bout.toString(); + assertThat(got).contains(DATASET_ID); + assertThat(got).contains("Create Training Pipeline Tabular Classification Response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTabularRegressionSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTabularRegressionSampleTest.java new file mode 100644 index 00000000000..c36ab9bb9c0 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTabularRegressionSampleTest.java @@ -0,0 +1,106 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateTrainingPipelineTabularRegressionSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = + System.getenv("TRAINING_PIPELINE_TABLES_REGRESSION_DATASET_ID"); + private static final String TARGET_COLUMN = "FLOAT_5000unique_REQUIRED"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_TABLES_REGRESSION_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(3); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void createTrainingPipelineTabularRegression() throws IOException { + // Act + String modelDisplayName = + String.format( + "temp_create_training_pipelinetabularregression_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineTabularRegressionSample.createTrainingPipelineTableRegression( + PROJECT, modelDisplayName, DATASET_ID, TARGET_COLUMN); + + // Assert + String got = bout.toString(); + assertThat(got).contains(DATASET_ID); + assertThat(got).contains("Create Training Pipeline Tabular Regression Response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextClassificationSampleTest.java new file mode 100644 index 00000000000..5b68dab26f6 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextClassificationSampleTest.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateTrainingPipelineTextClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = System.getenv("TRAINING_PIPELINE_TEXT_CLASS_DATASET_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_TEXT_CLASS_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateTrainingPipelineTextClassificationSample() throws IOException { + // Act + String trainingPipelineDisplayName = + String.format( + "temp_create_training_pipeline_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + String modelDisplayName = + String.format( + "temp_create_training_pipeline_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineTextClassificationSample.createTrainingPipelineTextClassificationSample( + PROJECT, trainingPipelineDisplayName, DATASET_ID, modelDisplayName); + + // Assert + String got = bout.toString(); + assertThat(got).contains(DATASET_ID); + assertThat(got).contains("Create Training Pipeline Text Classification Response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextEntityExtractionSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextEntityExtractionSampleTest.java new file mode 100644 index 00000000000..fc93ccb06da --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextEntityExtractionSampleTest.java @@ -0,0 +1,114 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateTrainingPipelineTextEntityExtractionSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = + System.getenv("TRAINING_PIPELINE_TEXT_ENTITY_DATASET_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_TEXT_ENTITY_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateTrainingPipelineTextEntityExtractionSample() throws IOException { + // Act + String trainingPipelineDisplayName = + String.format( + "temp_create_training_pipeline_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + String modelDisplayName = + String.format( + "temp_create_training_pipeline_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineTextEntityExtractionSample + .createTrainingPipelineTextEntityExtractionSample( + PROJECT, trainingPipelineDisplayName, DATASET_ID, modelDisplayName); + + // Assert + String got = bout.toString(); + assertThat(got).contains(DATASET_ID); + assertThat(got).contains("Create Training Pipeline Text Entity Extraction Response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextSentimentAnalysisSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextSentimentAnalysisSampleTest.java new file mode 100644 index 00000000000..b84598e54d9 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineTextSentimentAnalysisSampleTest.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class CreateTrainingPipelineTextSentimentAnalysisSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = System.getenv("TRAINING_PIPELINE_TEXT_SENTI_DATASET_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_TEXT_SENTI_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateTrainingPipelineTextSentimentAnalysisSample() throws IOException { + String tempUuid = UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26); + // Act + String trainingPipelineDisplayName = + String.format("temp_create_training_pipeline_test_%s", tempUuid); + + String modelDisplayName = + String.format("temp_create_training_pipeline_model_test_%s", tempUuid); + + CreateTrainingPipelineTextSentimentAnalysisSample + .createTrainingPipelineTextSentimentAnalysisSample( + PROJECT, trainingPipelineDisplayName, DATASET_ID, modelDisplayName); + + // Assert + String got = bout.toString(); + assertThat(got).contains(DATASET_ID); + assertThat(got).contains("Create Training Pipeline Text Sentiment Analysis Response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoActionRecognitionSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoActionRecognitionSampleTest.java new file mode 100644 index 00000000000..11fb905febf --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoActionRecognitionSampleTest.java @@ -0,0 +1,108 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class CreateTrainingPipelineVideoActionRecognitionSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = + System.getenv("TRAINING_PIPELINE_VIDEO_ACTION_DATASET_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_VIDEO_ACTION_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateTrainingPipelineVideoActionRecognitionSample() throws IOException { + // Act + String trainingPipelineDisplayName = + String.format( + "temp_create_training_pipeline_video_action_recognition_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + String modelDisplayName = + String.format( + "temp_create_training_pipeline_video_action_recognition_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineVideoActionRecognitionSample + .createTrainingPipelineVideoActionRecognitionSample( + PROJECT, trainingPipelineDisplayName, DATASET_ID, modelDisplayName); + + // Assert + String got = bout.toString(); + assertThat(got).contains(DATASET_ID); + assertThat(got).contains("response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoClassificationSampleTest.java new file mode 100644 index 00000000000..7a54fc65f8a --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoClassificationSampleTest.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateTrainingPipelineVideoClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = + System.getenv("TRAINING_PIPELINE_VIDEO_CLASS_DATASET_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_VIDEO_CLASS_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateTrainingPipelineVideoClassificationSample() throws IOException { + // Act + String trainingPipelineDisplayName = + String.format( + "temp_create_training_pipeline_video_classification_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + String modelDisplayName = + String.format( + "temp_create_training_pipeline_video_classification_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineVideoClassificationSample.createTrainingPipelineVideoClassification( + trainingPipelineDisplayName, DATASET_ID, modelDisplayName, PROJECT); + + // Assert + String got = bout.toString(); + assertThat(got).contains(DATASET_ID); + assertThat(got).contains("Create Training Pipeline Video Classification Response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoObjectTrackingSampleTest.java b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoObjectTrackingSampleTest.java new file mode 100644 index 00000000000..359cde9976a --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/CreateTrainingPipelineVideoObjectTrackingSampleTest.java @@ -0,0 +1,110 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class CreateTrainingPipelineVideoObjectTrackingSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = + System.getenv("TRAINING_PIPELINE_VIDEO_OBJECT_DETECT_DATASET_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String trainingPipelineId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TRAINING_PIPELINE_VIDEO_OBJECT_DETECT_DATASET_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Cancel the Training Pipeline + CancelTrainingPipelineSample.cancelTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String cancelResponse = bout.toString(); + assertThat(cancelResponse).contains("Cancelled the Training Pipeline"); + TimeUnit.MINUTES.sleep(2); + + // Delete the Training Pipeline + DeleteTrainingPipelineSample.deleteTrainingPipelineSample(PROJECT, trainingPipelineId); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Deleted Training Pipeline."); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testCreateTrainingPipelineVideoObjectTrackingSample() throws IOException { + // Act + String trainingPipelineDisplayName = + String.format( + "temp_create_training_pipeline_video_object_tracking_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + String modelDisplayName = + String.format( + "temp_create_training_pipeline_video_object_tracking_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + + CreateTrainingPipelineVideoObjectTrackingSample.createTrainingPipelineVideoObjectTracking( + trainingPipelineDisplayName, DATASET_ID, modelDisplayName, PROJECT); + + // Assert + String got = bout.toString(); + assertThat(got).contains(DATASET_ID); + assertThat(got).contains("Create Training Pipeline Video Object Tracking Response"); + trainingPipelineId = got.split("Name: ")[1].split("trainingPipelines/")[1].split("\n")[0]; + } +} diff --git a/aiplatform/src/test/java/aiplatform/DeployModelCustomTrainedModelSampleTest.java b/aiplatform/src/test/java/aiplatform/DeployModelCustomTrainedModelSampleTest.java new file mode 100644 index 00000000000..71a0d53fa0a --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/DeployModelCustomTrainedModelSampleTest.java @@ -0,0 +1,97 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import io.grpc.StatusRuntimeException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class DeployModelCustomTrainedModelSampleTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "4992732768149438464"; + private static final String ENDPOINT_ID = "4366591682456584192"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + + // Undeploy the model + try { + UndeployModelSample.undeployModelSample(PROJECT_ID, ENDPOINT_ID, MODEL_ID); + } catch (IOException | InterruptedException | ExecutionException | TimeoutException e) { + e.printStackTrace(); + } + } + + @Ignore("Issues with undeploy") + @Test + public void testDeployModelCustomTrainedModelSample() throws TimeoutException { + // 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. + String deployedModelDisplayName = + String.format( + "temp_deploy_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + try { + DeployModelCustomTrainedModelSample.deployModelCustomTrainedModelSample( + PROJECT_ID, ENDPOINT_ID, MODEL_ID, deployedModelDisplayName); + // Assert + String got = bout.toString(); + assertThat(got).contains("deployModelResponse"); + } catch (StatusRuntimeException | ExecutionException | InterruptedException | IOException e) { + assertThat(e.getMessage()).contains("is not found."); + } + } +} diff --git a/aiplatform/src/test/java/aiplatform/DeployModelSampleTest.java b/aiplatform/src/test/java/aiplatform/DeployModelSampleTest.java new file mode 100644 index 00000000000..e8878a9658f --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/DeployModelSampleTest.java @@ -0,0 +1,87 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import io.grpc.StatusRuntimeException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class DeployModelSampleTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "00000000000000000"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testDeployModelSample() throws TimeoutException { + // 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. + String deployedModelDisplayName = + String.format( + "temp_deploy_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + try { + DeployModelSample.deployModelSample( + PROJECT_ID, deployedModelDisplayName, "4366591682456584192", MODEL_ID); + // Assert + String got = bout.toString(); + assertThat(got).contains("is not found."); + } catch (StatusRuntimeException | ExecutionException | InterruptedException | IOException e) { + assertThat(e.getMessage()).contains("is not found."); + } + } +} diff --git a/aiplatform/src/test/java/aiplatform/ExportModelSampleTest.java b/aiplatform/src/test/java/aiplatform/ExportModelSampleTest.java new file mode 100644 index 00000000000..20e9725f1e5 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/ExportModelSampleTest.java @@ -0,0 +1,94 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ExportModelSampleTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "3422489426196955136"; + private static final String GCS_DESTINATION_URI_PREFIX = + "gs://ucaip-samples-test-output/tmp/export_model_test"; + private static final String EXPORT_FORMAT = "tf-saved-model"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // Delete the export model + String bucketName; + String objectName; + bucketName = GCS_DESTINATION_URI_PREFIX.split("/", 4)[2]; + objectName = (GCS_DESTINATION_URI_PREFIX.split("/", 4)[3]).concat("model-" + MODEL_ID); + DeleteExportModelSample.deleteExportModelSample(PROJECT_ID, bucketName, objectName); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Export Model Deleted"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testExportModelSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + ExportModelSample.exportModelSample( + PROJECT_ID, MODEL_ID, GCS_DESTINATION_URI_PREFIX, EXPORT_FORMAT); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Export Model Response: "); + } +} diff --git a/aiplatform/src/test/java/aiplatform/ExportModelTabularClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/ExportModelTabularClassificationSampleTest.java new file mode 100644 index 00000000000..967efab654f --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/ExportModelTabularClassificationSampleTest.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class ExportModelTabularClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "6036688272397172736"; + private static final String GCS_DESTINATION_URI_PREFIX = + "gs://ucaip-samples-test-output/tmp/export_model_test"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + // Delete the export model + String bucketName = GCS_DESTINATION_URI_PREFIX.split("/", 4)[2]; + String objectName = (GCS_DESTINATION_URI_PREFIX.split("/", 4)[3]).concat("model-" + MODEL_ID); + DeleteExportModelSample.deleteExportModelSample(PROJECT, bucketName, objectName); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Export Model Deleted"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void exportModelTabularClassification() + throws InterruptedException, ExecutionException, TimeoutException, IOException { + // Act + ExportModelTabularClassificationSample.exportModelTableClassification( + GCS_DESTINATION_URI_PREFIX, PROJECT, MODEL_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Export Model Tabular Classification Response: "); + } +} diff --git a/aiplatform/src/test/java/aiplatform/ExportModelVideoActionRecognitionSampleTest.java b/aiplatform/src/test/java/aiplatform/ExportModelVideoActionRecognitionSampleTest.java new file mode 100644 index 00000000000..c622eaf154d --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/ExportModelVideoActionRecognitionSampleTest.java @@ -0,0 +1,91 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class ExportModelVideoActionRecognitionSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = + System.getenv("EXPORT_MODEL_VIDEO_ACTION_RECOGNITION_MODEL_ID"); + private static final String GCS_DESTINATION_URI_PREFIX = + "gs://ucaip-samples-test-output/tmp/export_model_video_action_recognition_sample"; + private static final String EXPORT_FORMAT = "tf-saved-model"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("EXPORT_MODEL_VIDEO_ACTION_RECOGNITION_MODEL_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + // Delete the export model + String bucketName = GCS_DESTINATION_URI_PREFIX.split("/", 4)[2]; + String objectName = (GCS_DESTINATION_URI_PREFIX.split("/", 4)[3]).concat("model-" + MODEL_ID); + DeleteExportModelSample.deleteExportModelSample(PROJECT, bucketName, objectName); + + // Assert + String deleteResponse = bout.toString(); + assertThat(deleteResponse).contains("Export Model Deleted"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testExportModelVideoActionRecognitionSample() + throws InterruptedException, ExecutionException, TimeoutException, IOException { + // Act + ExportModelVideoActionRecognitionSample.exportModelVideoActionRecognitionSample( + PROJECT, MODEL_ID, GCS_DESTINATION_URI_PREFIX, EXPORT_FORMAT); + + // Assert + String got = bout.toString(); + assertThat(got).contains("exportModelResponse: "); + } +} diff --git a/aiplatform/src/test/java/aiplatform/FeatureValuesSamplesTest.java b/aiplatform/src/test/java/aiplatform/FeatureValuesSamplesTest.java new file mode 100644 index 00000000000..b4e6bba320d --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/FeatureValuesSamplesTest.java @@ -0,0 +1,345 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import com.google.cloud.aiplatform.v1.Feature.ValueType; +import com.google.cloud.bigquery.BigQuery; +import com.google.cloud.bigquery.BigQuery.DatasetDeleteOption; +import com.google.cloud.bigquery.BigQueryException; +import com.google.cloud.bigquery.BigQueryOptions; +import com.google.cloud.bigquery.Dataset; +import com.google.cloud.bigquery.DatasetId; +import com.google.cloud.bigquery.DatasetInfo; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.text.SimpleDateFormat; +import java.util.Arrays; +import java.util.Date; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class FeatureValuesSamplesTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final int MIN_NODE_COUNT = 1; + private static final int MAX_NODE_COUNT = 2; + private static final String DESCRIPTION = "Test Description"; + private static final boolean USE_FORCE = true; + private static final ValueType VALUE_TYPE = ValueType.STRING; + private static final String QUERY = "value_type=STRING"; + private static final String ENTITY_ID_FIELD = "movie_id"; + private static final String FEATURE_TIME_FIELD = "update_time"; + private static final String GCS_SOURCE_URI = + "gs://cloud-samples-data-us-central1/vertex-ai/feature-store/datasets/movies.avro"; + private static final int WORKER_COUNT = 2; + private static final String INPUT_CSV_FILE = + "gs://cloud-samples-data-us-central1/vertex-ai/feature-store/datasets/movie_prediction.csv"; + private static final List FEATURE_SELECTOR_IDS = + Arrays.asList("title", "genres", "average_rating"); + private static final String LOCATION = "us-central1"; + private static final String ENDPOINT = "us-central1-aiplatform.googleapis.com:443"; + private static final int TIMEOUT = 900; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String featurestoreId; + private String destinationTableUri; + private Date date; + private SimpleDateFormat dateFormat; + private String datasetName; + private String destinationTableName; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + date = new Date(); + dateFormat = new SimpleDateFormat("yyyyMMddHHmmSSS"); + datasetName = "movie_predictions" + dateFormat.format(date); + destinationTableName = "training_data"; + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + static void createBigQueryDataset(String projectId, String datasetName, String location) { + try { + // Initialize client that will be used to send requests. This client only needs + // to be created + // once, and can be reused for multiple requests. + BigQuery bigquery = + BigQueryOptions.newBuilder() + .setLocation(location) + .setProjectId(projectId) + .build() + .getService(); + DatasetInfo datasetInfo = DatasetInfo.newBuilder(datasetName).build(); + + Dataset newDataset = bigquery.create(datasetInfo); + String newDatasetName = newDataset.getDatasetId().getDataset(); + System.out.println(newDatasetName + " created successfully"); + } catch (BigQueryException e) { + System.out.format("Dataset was not created. %n%s", e.toString()); + } + } + + static void deleteBigQueryDataset(String projectId, String datasetName, String location) { + try { + // Initialize client that will be used to send requests. This client only needs to be created + // once, and can be reused for multiple requests. + BigQuery bigquery = + BigQueryOptions.newBuilder() + .setLocation(location) + .setProjectId(projectId) + .build() + .getService(); + + DatasetId datasetId = DatasetId.of(projectId, datasetName); + boolean success = bigquery.delete(datasetId, DatasetDeleteOption.deleteContents()); + if (success) { + System.out.println("Dataset deleted successfully"); + } else { + System.out.println("Dataset was not found"); + } + } catch (BigQueryException e) { + System.out.format("Dataset was not deleted. %n%s", e.toString()); + } + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + + // Delete the featurestore + DeleteFeaturestoreSample.deleteFeaturestoreSample( + PROJECT_ID, featurestoreId, USE_FORCE, LOCATION, ENDPOINT, 300); + + // Assert + String deleteFeaturestoreResponse = bout.toString(); + assertThat(deleteFeaturestoreResponse).contains("Deleted Featurestore"); + + // Delete the big query dataset + deleteBigQueryDataset(PROJECT_ID, datasetName, LOCATION); + + // Assert + String deleteBigQueryResponse = bout.toString(); + assertThat(deleteBigQueryResponse).contains("Dataset deleted successfully"); + + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testFeatureValuesSamples() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Create the featurestore + String tempUuid = UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 23); + String id = String.format("temp_feature_values_samples_test_%s", tempUuid); + CreateFeaturestoreSample.createFeaturestoreSample( + PROJECT_ID, id, MIN_NODE_COUNT, MAX_NODE_COUNT, LOCATION, ENDPOINT, 900); + + // Assert + String createFeaturestoreResponse = bout.toString(); + assertThat(createFeaturestoreResponse).contains("Create Featurestore Response"); + featurestoreId = + createFeaturestoreResponse.split("Name: ")[1].split("featurestores/")[1].split("\n")[0] + .trim(); + + // Create the entity type + String entityTypeId = "movies"; + CreateEntityTypeSample.createEntityTypeSample( + PROJECT_ID, featurestoreId, entityTypeId, DESCRIPTION, LOCATION, ENDPOINT, 900); + + // Assert + String createEntityTypeResponse = bout.toString(); + assertThat(createEntityTypeResponse).contains("Create Entity Type Response"); + + // Create the feature + String featureTempUuid = UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 25); + String featureId = String.format("temp_feature_feature_test_%s", featureTempUuid); + CreateFeatureSample.createFeatureSample( + PROJECT_ID, + featurestoreId, + entityTypeId, + featureId, + DESCRIPTION, + VALUE_TYPE, + LOCATION, + ENDPOINT, + 900); + + // Assert + String createFeatureResponse = bout.toString(); + assertThat(createFeatureResponse).contains("Create Feature Response"); + + // Get the feature + GetFeatureSample.getFeatureSample( + PROJECT_ID, featurestoreId, entityTypeId, featureId, LOCATION, ENDPOINT); + + // Assert + String getFeatureResponse = bout.toString(); + assertThat(getFeatureResponse).contains("Get Feature Response"); + + // List features + ListFeaturesSample.listFeaturesSample( + PROJECT_ID, featurestoreId, entityTypeId, LOCATION, ENDPOINT); + + // Assert + String listfeatureResponse = bout.toString(); + assertThat(listfeatureResponse).contains("List Features Response"); + + // List features + ListFeaturesAsyncSample.listFeaturesAsyncSample( + PROJECT_ID, featurestoreId, entityTypeId, LOCATION, ENDPOINT); + + // Assert + String listfeatureAsyncResponse = bout.toString(); + assertThat(listfeatureAsyncResponse).contains("List Features Async Response"); + + // Search features + SearchFeaturesSample.searchFeaturesSample(PROJECT_ID, QUERY, LOCATION, ENDPOINT); + + // Assert + String searchFeaturesResponse = bout.toString(); + assertThat(searchFeaturesResponse).contains("Search Features Response"); + + // Search features + SearchFeaturesAsyncSample.searchFeaturesAsyncSample(PROJECT_ID, QUERY, LOCATION, ENDPOINT); + + // Assert + String searchFeaturesAsyncResponse = bout.toString(); + assertThat(searchFeaturesAsyncResponse).contains("Search Features Async Response"); + + // Delete the feature + DeleteFeatureSample.deleteFeatureSample( + PROJECT_ID, featurestoreId, entityTypeId, featureId, LOCATION, ENDPOINT, 300); + + // Assert + String deleteFeatureResponse = bout.toString(); + assertThat(deleteFeatureResponse).contains("Deleted Feature"); + + // Batch create features + BatchCreateFeaturesSample.batchCreateFeaturesSample( + PROJECT_ID, featurestoreId, entityTypeId, LOCATION, ENDPOINT, TIMEOUT); + + // Assert + String batchCreateFeaturesResponse = bout.toString(); + assertThat(batchCreateFeaturesResponse).contains("Batch Create Features Response"); + + // Import feature values + ImportFeatureValuesSample.importFeatureValuesSample( + PROJECT_ID, + featurestoreId, + entityTypeId, + GCS_SOURCE_URI, + ENTITY_ID_FIELD, + FEATURE_TIME_FIELD, + WORKER_COUNT, + LOCATION, + ENDPOINT, + TIMEOUT); + + // Assert + String importFeatureValuesResponse = bout.toString(); + assertThat(importFeatureValuesResponse).contains("Import Feature Values Response"); + + // Create the big query dataset + createBigQueryDataset(PROJECT_ID, datasetName, LOCATION); + destinationTableUri = + String.format("bq://%s.%s.%s_full", PROJECT_ID, datasetName, destinationTableName); + + // Assert + String createBigQueryDatasetResponse = bout.toString(); + assertThat(createBigQueryDatasetResponse).contains(datasetName + " created successfully"); + + // Export feature values + ExportFeatureValuesSample.exportFeatureValuesSample( + PROJECT_ID, + featurestoreId, + entityTypeId, + destinationTableUri, + FEATURE_SELECTOR_IDS, + LOCATION, + ENDPOINT, + TIMEOUT); + + // Assert + String exportFeatureValuesResponse = bout.toString(); + assertThat(exportFeatureValuesResponse).contains("Export Feature Values Response"); + + destinationTableUri = + String.format("bq://%s.%s.%s_snapshot", PROJECT_ID, datasetName, destinationTableName); + + // Snapshot export feature values + ExportFeatureValuesSnapshotSample.exportFeatureValuesSnapshotSample( + PROJECT_ID, + featurestoreId, + entityTypeId, + destinationTableUri, + FEATURE_SELECTOR_IDS, + LOCATION, + ENDPOINT, + TIMEOUT); + + // Assert + String snapshotResponse = bout.toString(); + assertThat(snapshotResponse).contains("Snapshot Export Feature Values Response"); + + destinationTableUri = + String.format("bq://%s.%s.%s_batchRead", PROJECT_ID, datasetName, destinationTableName); + + // Batch read feature values + BatchReadFeatureValuesSample.batchReadFeatureValuesSample( + PROJECT_ID, + featurestoreId, + entityTypeId, + INPUT_CSV_FILE, + destinationTableUri, + FEATURE_SELECTOR_IDS, + LOCATION, + ENDPOINT, + TIMEOUT); + + // Assert + String batchReadFeatureValuesResponse = bout.toString(); + assertThat(batchReadFeatureValuesResponse).contains("Batch Read Feature Values Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/FeaturestoreSamplesTest.java b/aiplatform/src/test/java/aiplatform/FeaturestoreSamplesTest.java new file mode 100644 index 00000000000..74fcbde5b01 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/FeaturestoreSamplesTest.java @@ -0,0 +1,220 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class FeaturestoreSamplesTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final int MIN_NODE_COUNT = 1; + private static final int MAX_NODE_COUNT = 2; + private static final int FIXED_NODE_COUNT = 2; + private static final String DESCRIPTION = "Test Description"; + private static final int MONITORING_INTERVAL_DAYS = 1; + private static final boolean USE_FORCE = true; + private static final String LOCATION = "us-central1"; + private static final String ENDPOINT = "us-central1-aiplatform.googleapis.com:443"; + private static final int TIMEOUT = 900; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String featurestoreId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + + // Delete the featurestore + DeleteFeaturestoreSample.deleteFeaturestoreSample( + PROJECT_ID, featurestoreId, USE_FORCE, LOCATION, ENDPOINT, 60); + + // Assert + String deleteFeaturestoreResponse = bout.toString(); + assertThat(deleteFeaturestoreResponse).contains("Deleted Featurestore"); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testCreateFeaturestoreSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Create the featurestore + String tempUuid = UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 25); + String id = String.format("temp_featurestore_samples_test_%s", tempUuid); + CreateFeaturestoreFixedNodesSample.createFeaturestoreFixedNodesSample( + PROJECT_ID, id, FIXED_NODE_COUNT, LOCATION, ENDPOINT, 900); + + // Assert + String createFeaturestoreResponse = bout.toString(); + assertThat(createFeaturestoreResponse).contains("Create Featurestore Response"); + featurestoreId = + createFeaturestoreResponse.split("Name: ")[1].split("featurestores/")[1].split("\n")[0] + .trim(); + + // Get the featurestore + GetFeaturestoreSample.getFeaturestoreSample(PROJECT_ID, featurestoreId, LOCATION, ENDPOINT); + + // Assert + String getFeaturestoreResponse = bout.toString(); + assertThat(getFeaturestoreResponse).contains("Get Featurestore Response"); + + // Update the featurestore with autoscaling + UpdateFeaturestoreSample.updateFeaturestoreSample( + PROJECT_ID, featurestoreId, MIN_NODE_COUNT, MAX_NODE_COUNT, LOCATION, ENDPOINT, TIMEOUT); + + // Assert + String updateFeaturestoreResponse = bout.toString(); + assertThat(updateFeaturestoreResponse).contains("Update Featurestore Response"); + + // List featurestores + ListFeaturestoresSample.listFeaturestoresSample(PROJECT_ID, LOCATION, ENDPOINT); + + // Assert + String listFeaturestoresResponse = bout.toString(); + assertThat(listFeaturestoresResponse).contains("List Featurestores Response"); + + // Update the featurestore with fixed nodes + UpdateFeaturestoreFixedNodesSample.updateFeaturestoreFixedNodesSample( + PROJECT_ID, featurestoreId, FIXED_NODE_COUNT, LOCATION, ENDPOINT, TIMEOUT); + + // Assert + String updateFeaturestoreFixedNodesResponse = bout.toString(); + assertThat(updateFeaturestoreFixedNodesResponse) + .contains("Update Featurestore Fixed Nodes Response"); + + // List featurestores + ListFeaturestoresAsyncSample.listFeaturestoresAsyncSample(PROJECT_ID, LOCATION, ENDPOINT); + + // Assert + String listFeaturestoresAsyncResponse = bout.toString(); + assertThat(listFeaturestoresAsyncResponse).contains("List Featurestores Async Response"); + + // Create the entity type + String entityTypeTempUuid = UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 14); + String entityTypeId = String.format("temp_featurestore_samples_test_%s", entityTypeTempUuid); + CreateEntityTypeSample.createEntityTypeSample( + PROJECT_ID, featurestoreId, entityTypeId, DESCRIPTION, LOCATION, ENDPOINT, TIMEOUT); + + // Assert + String createEntityTypeResponse = bout.toString(); + assertThat(createEntityTypeResponse).contains("Create Entity Type Response"); + + // Get the entity type + GetEntityTypeSample.getEntityTypeSample( + PROJECT_ID, featurestoreId, entityTypeId, LOCATION, ENDPOINT); + + // Assert + String getEntityTypeResponse = bout.toString(); + assertThat(getEntityTypeResponse).contains("Get Entity Type Response"); + + // Create the entity type + String entityTypeMonitoringTempUuid = + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 14); + String entityTypeMonitoringId = + String.format("temp_featurestore_samples_test_%s", entityTypeMonitoringTempUuid); + CreateEntityTypeMonitoringSample.createEntityTypeMonitoringSample( + PROJECT_ID, + featurestoreId, + entityTypeMonitoringId, + DESCRIPTION, + MONITORING_INTERVAL_DAYS, + LOCATION, + ENDPOINT, + TIMEOUT); + + // Assert + String createEntityTypeMonitoringResponse = bout.toString(); + assertThat(createEntityTypeMonitoringResponse) + .contains("Create Entity Type Monitoring Response"); + + // List entity types + ListEntityTypesSample.listEntityTypesSample(PROJECT_ID, featurestoreId, LOCATION, ENDPOINT); + + // Assert + String listEntityTypeResponse = bout.toString(); + assertThat(listEntityTypeResponse).contains("List Entity Types Response"); + + // Update the entity type + UpdateEntityTypeSample.updateEntityTypeSample( + PROJECT_ID, featurestoreId, entityTypeId, DESCRIPTION, LOCATION, ENDPOINT); + + // Assert + String updateEntityTypeResponse = bout.toString(); + assertThat(updateEntityTypeResponse).contains("Update Entity Type Response"); + + // Update the entity type + UpdateEntityTypeMonitoringSample.updateEntityTypeMonitoringSample( + PROJECT_ID, featurestoreId, entityTypeId, MONITORING_INTERVAL_DAYS, LOCATION, ENDPOINT); + + // Assert + String updateEntityTypeMonitoringResponse = bout.toString(); + assertThat(updateEntityTypeMonitoringResponse) + .contains("Update Entity Type Monitoring Response"); + + // List entity types + ListEntityTypesAsyncSample.listEntityTypesAsyncSample( + PROJECT_ID, featurestoreId, LOCATION, ENDPOINT); + + // Assert + String listEntityTypeAsyncResponse = bout.toString(); + assertThat(listEntityTypeAsyncResponse).contains("List Entity Types Async Response"); + + // Delete the entity type + DeleteEntityTypeSample.deleteEntityTypeSample( + PROJECT_ID, featurestoreId, entityTypeId, LOCATION, ENDPOINT, TIMEOUT); + + // Assert + String deleteEntityTypeResponse = bout.toString(); + assertThat(deleteEntityTypeResponse).contains("Deleted Entity Type"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetHyperparameterTuningJobSampleTest.java b/aiplatform/src/test/java/aiplatform/GetHyperparameterTuningJobSampleTest.java new file mode 100644 index 00000000000..685768000d1 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetHyperparameterTuningJobSampleTest.java @@ -0,0 +1,73 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class GetHyperparameterTuningJobSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String HYPERPARAMETER_TUNING_JOB_ID = System.getenv("GET_HP_TUNING_JOB_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("GET_HP_TUNING_JOB_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetHyperparameterTuningJobSample() throws IOException { + GetHyperparameterTuningJobSample.getHyperparameterTuningJobSample( + PROJECT, HYPERPARAMETER_TUNING_JOB_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(HYPERPARAMETER_TUNING_JOB_ID); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationImageClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationImageClassificationSampleTest.java new file mode 100644 index 00000000000..27174f55f32 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationImageClassificationSampleTest.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetModelEvaluationImageClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "3512561418744365056"; + private static final String EVALUATION_ID = "9035588644970168320"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelEvaluationImageClassificationSample() throws IOException { + // Act + GetModelEvaluationImageClassificationSample.getModelEvaluationImageClassificationSample( + PROJECT, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model Evaluation Image Classification Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationImageObjectDetectionSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationImageObjectDetectionSampleTest.java new file mode 100644 index 00000000000..946482f6fc3 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationImageObjectDetectionSampleTest.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetModelEvaluationImageObjectDetectionSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "3512561418744365056"; + private static final String EVALUATION_ID = "9035588644970168320"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelEvaluationImageObjectDetectionSample() throws IOException { + // Act + GetModelEvaluationImageObjectDetectionSample.getModelEvaluationImageObjectDetectionSample( + PROJECT, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model Evaluation Image Object Detection Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationSampleTest.java new file mode 100644 index 00000000000..d2f4e03d0e9 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationSampleTest.java @@ -0,0 +1,78 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetModelEvaluationSampleTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "3512561418744365056"; + private static final String EVALUATION_ID = "9035588644970168320"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelEvaluationSample() throws IOException { + // Act + GetModelEvaluationSample.getModelEvaluationSample(PROJECT_ID, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model Evaluation Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationSliceSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationSliceSampleTest.java new file mode 100644 index 00000000000..b02103e89ed --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationSliceSampleTest.java @@ -0,0 +1,80 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetModelEvaluationSliceSampleTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "3512561418744365056"; + private static final String EVALUATION_ID = "9035588644970168320"; + private static final String SLICE_ID = "6481571820677004173"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelEvaluationSliceSample() throws IOException { + // Act + GetModelEvaluationSliceSample.getModelEvaluationSliceSample( + PROJECT_ID, MODEL_ID, EVALUATION_ID, SLICE_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(EVALUATION_ID); + assertThat(got).contains("Get Model Evaluation Slice Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationTabularClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationTabularClassificationSampleTest.java new file mode 100644 index 00000000000..23b0f28780e --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationTabularClassificationSampleTest.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class GetModelEvaluationTabularClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "6036688272397172736"; + private static final String EVALUATION_ID = "1866113044163962838"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void getModelEvaluationTabularClassification() throws IOException { + // Act + GetModelEvaluationTabularClassificationSample.getModelEvaluationTabularClassification( + PROJECT, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model Evaluation Tabular Classification Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationTabularRegressionSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationTabularRegressionSampleTest.java new file mode 100644 index 00000000000..bb5ec79b12a --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationTabularRegressionSampleTest.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class GetModelEvaluationTabularRegressionSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "8842430840248991744"; + private static final String EVALUATION_ID = "4944816689650806017"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void getModelEvaluationTabularRegression() throws IOException { + // Act + GetModelEvaluationTabularRegressionSample.getModelEvaluationTabularRegression( + PROJECT, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model Evaluation Tabular Regression Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationTextClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationTextClassificationSampleTest.java new file mode 100644 index 00000000000..4e13470cd5a --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationTextClassificationSampleTest.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetModelEvaluationTextClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "7827432074230366208"; + private static final String EVALUATION_ID = "5064258198559522816"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelEvaluationTextClassificationSample() throws IOException { + // Act + GetModelEvaluationTextClassificationSample.getModelEvaluationTextClassificationSample( + PROJECT, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model Evaluation Text Classification Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationTextEntityExtractionSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationTextEntityExtractionSampleTest.java new file mode 100644 index 00000000000..5881a34296b --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationTextEntityExtractionSampleTest.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetModelEvaluationTextEntityExtractionSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "6305215400179138560"; + private static final String EVALUATION_ID = "1754112472442208256"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelEvaluationTextEntityExtractionSample() throws IOException { + // Act + GetModelEvaluationTextEntityExtractionSample.getModelEvaluationTextEntityExtractionSample( + PROJECT, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model Evaluation Text Entity Extraction Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationTextSentimentAnalysisSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationTextSentimentAnalysisSampleTest.java new file mode 100644 index 00000000000..cca27c67a86 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationTextSentimentAnalysisSampleTest.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetModelEvaluationTextSentimentAnalysisSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "4792568875336073216"; + private static final String EVALUATION_ID = "3347225656252432384"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelEvaluationTextSentimentAnalysisSample() throws IOException { + // Act + GetModelEvaluationTextSentimentAnalysisSample.getModelEvaluationTextSentimentAnalysisSample( + PROJECT, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model Evaluation Text Sentiment Analysis Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoActionRecognitionSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoActionRecognitionSampleTest.java new file mode 100644 index 00000000000..549f7172c9d --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoActionRecognitionSampleTest.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class GetModelEvaluationVideoActionRecognitionSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = System.getenv("VIDEO_ACTION_MODEL_ID"); + private static final String EVALUATION_ID = System.getenv("VIDEO_ACTION_EVALUATION_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("VIDEO_ACTION_MODEL_ID"); + requireEnvVar("VIDEO_ACTION_EVALUATION_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelEvaluationVideoActionRecognitionSample() throws IOException { + // Act + GetModelEvaluationVideoActionRecognitionSample.getModelEvaluationVideoActionRecognitionSample( + PROJECT, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("response:"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoClassificationSampleTest.java new file mode 100644 index 00000000000..26a4628fb8e --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoClassificationSampleTest.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class GetModelEvaluationVideoClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "8596984660557299712"; + private static final String EVALUATION_ID = "7092045712224944128"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelEvaluationVideoClassificationSample() throws IOException { + // Act + GetModelEvaluationVideoClassificationSample.getModelEvaluationVideoClassification( + PROJECT, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model Evaluation Video Classification Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoObjectTrackingSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoObjectTrackingSampleTest.java new file mode 100644 index 00000000000..7657b725537 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelEvaluationVideoObjectTrackingSampleTest.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class GetModelEvaluationVideoObjectTrackingSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "8609932509485989888"; + private static final String EVALUATION_ID = "6016811301190238208"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelEvaluationVideoObjectTrackingSample() throws IOException { + // Act + GetModelEvaluationVideoObjectTrackingSample.getModelEvaluationVideoObjectTracking( + PROJECT, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model Evaluation Video Object Tracking Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetModelSampleTest.java b/aiplatform/src/test/java/aiplatform/GetModelSampleTest.java new file mode 100644 index 00000000000..59507901243 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetModelSampleTest.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class GetModelSampleTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "3512561418744365056"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetModelSample() throws IOException { + // Act + GetModelSample.getModelSample(PROJECT_ID, MODEL_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(MODEL_ID); + assertThat(got).contains("Get Model response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/GetTrainingPipelineSampleTest.java b/aiplatform/src/test/java/aiplatform/GetTrainingPipelineSampleTest.java new file mode 100644 index 00000000000..41d5c09169c --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/GetTrainingPipelineSampleTest.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class GetTrainingPipelineSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String TRAINING_PIPELINE_ID = System.getenv("GET_TRAINING_PIPELINE_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("GET_TRAINING_PIPELINE_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testGetTrainingPipelineSample() throws IOException { + // Act + GetTrainingPipelineSample.getTrainingPipeline(PROJECT, TRAINING_PIPELINE_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(TRAINING_PIPELINE_ID); + assertThat(got).contains("Get Training Pipeline Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/ImportDataImageClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/ImportDataImageClassificationSampleTest.java new file mode 100644 index 00000000000..a490fa4d8ee --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/ImportDataImageClassificationSampleTest.java @@ -0,0 +1,133 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1beta1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.Dataset; +import com.google.cloud.aiplatform.v1beta1.DatasetName; +import com.google.cloud.aiplatform.v1beta1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1beta1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1beta1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.LocationName; +import com.google.protobuf.Empty; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ImportDataImageClassificationSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String LOCATION = "us-central1"; + + private static final String GCS_SOURCE_URI = "gs://ucaip-sample-resources/input.jsonl"; + private String datasetId; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + + // create a temp dataset for importing data + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"; + LocationName locationName = LocationName.of(PROJECT, LOCATION); + Dataset dataset = + Dataset.newBuilder() + .setDisplayName("test_dataset_display_name") + .setMetadataSchemaUri(metadataSchemaUri) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + Dataset datasetResponse = datasetFuture.get(120, TimeUnit.SECONDS); + String[] datasetValues = datasetResponse.getName().split("/"); + datasetId = datasetValues[datasetValues.length - 1]; + } + } + + @After + public void tearDown() throws InterruptedException, ExecutionException, IOException { + // delete the temp dataset + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + DatasetName datasetName = DatasetName.of(PROJECT, LOCATION, datasetId); + + OperationFuture operationFuture = + datasetServiceClient.deleteDatasetAsync(datasetName); + operationFuture.get(); + } + + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testImportDataSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + ImportDataImageClassificationSample.importDataImageClassificationSample( + PROJECT, datasetId, GCS_SOURCE_URI); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Import Data Image Classification Response: "); + } +} diff --git a/aiplatform/src/test/java/aiplatform/ImportDataImageObjectDetectionSampleTest.java b/aiplatform/src/test/java/aiplatform/ImportDataImageObjectDetectionSampleTest.java new file mode 100644 index 00000000000..5c599cbc720 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/ImportDataImageObjectDetectionSampleTest.java @@ -0,0 +1,133 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1beta1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.Dataset; +import com.google.cloud.aiplatform.v1beta1.DatasetName; +import com.google.cloud.aiplatform.v1beta1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1beta1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1beta1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.LocationName; +import com.google.protobuf.Empty; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ImportDataImageObjectDetectionSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String LOCATION = "us-central1"; + private static final String GCS_SOURCE_URI = "gs://ucaip-sample-resources/input.jsonl"; + + private String datasetId; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() + throws InterruptedException, ExecutionException, TimeoutException, IOException { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + + // create a temp dataset for importing data + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/metadata/image_1.0.0.yaml"; + LocationName locationName = LocationName.of(PROJECT, LOCATION); + Dataset dataset = + Dataset.newBuilder() + .setDisplayName("test_dataset_display_name") + .setMetadataSchemaUri(metadataSchemaUri) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + Dataset datasetResponse = datasetFuture.get(120, TimeUnit.SECONDS); + String[] datasetValues = datasetResponse.getName().split("/"); + datasetId = datasetValues[datasetValues.length - 1]; + } + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, IOException, TimeoutException { + // delete the temp dataset + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + DatasetName datasetName = DatasetName.of(PROJECT, LOCATION, datasetId); + + OperationFuture operationFuture = + datasetServiceClient.deleteDatasetAsync(datasetName); + operationFuture.get(); + } + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testImportDataSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + ImportDataImageObjectDetectionSample.importDataImageObjectDetectionSample( + PROJECT, datasetId, GCS_SOURCE_URI); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Import Data Image Object Detection Response: "); + } +} diff --git a/aiplatform/src/test/java/aiplatform/ImportDataSampleTest.java b/aiplatform/src/test/java/aiplatform/ImportDataSampleTest.java new file mode 100644 index 00000000000..dcfaceb9f55 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/ImportDataSampleTest.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import io.grpc.StatusRuntimeException; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ImportDataSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String DATASET_ID = "000000000000000000000"; + + private static final String GCS_SOURCE_URI = + "gs://automl-cloud-dataset/SMSSpamCollection_train_dataset_2.csv"; + + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testImportDataSample() throws TimeoutException { + // As import data into dataset can take a long time, instead try to import data into a + // nonexistent dataset and confirm that the model was not found, but other + // elements of the request were valid. + try { + ImportDataTextClassificationSingleLabelSample.importDataTextClassificationSingleLabelSample( + PROJECT, DATASET_ID, GCS_SOURCE_URI); + // Assert + String got = bout.toString(); + assertThat(got).contains("The Dataset does not exist."); + } catch (StatusRuntimeException | ExecutionException | InterruptedException | IOException e) { + assertThat(e.getMessage()).contains("The Dataset does not exist."); + } + } +} diff --git a/aiplatform/src/test/java/aiplatform/ImportDataVideoActionRecognitionSampleTest.java b/aiplatform/src/test/java/aiplatform/ImportDataVideoActionRecognitionSampleTest.java new file mode 100644 index 00000000000..34102d77946 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/ImportDataVideoActionRecognitionSampleTest.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1beta1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.Dataset; +import com.google.cloud.aiplatform.v1beta1.DatasetName; +import com.google.cloud.aiplatform.v1beta1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1beta1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1beta1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.LocationName; +import com.google.protobuf.Empty; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class ImportDataVideoActionRecognitionSampleTest { + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String LOCATION = "us-central1"; + private static final String GCS_SOURCE_URI = + "gs://automl-video-demo-data/ucaip-var/swimrun.jsonl"; + + private String datasetId; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + + // create a temp dataset for importing data + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/metadata/video_1.0.0.yaml"; + LocationName locationName = LocationName.of(PROJECT, LOCATION); + Dataset dataset = + Dataset.newBuilder() + .setDisplayName("test_dataset_display_name") + .setMetadataSchemaUri(metadataSchemaUri) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + Dataset datasetResponse = datasetFuture.get(300, TimeUnit.SECONDS); + String[] datasetValues = datasetResponse.getName().split("/"); + datasetId = datasetValues[datasetValues.length - 1]; + } + } + + @After + public void tearDown() throws InterruptedException, ExecutionException, IOException { + // delete the temp dataset + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + DatasetName datasetName = DatasetName.of(PROJECT, LOCATION, datasetId); + + OperationFuture operationFuture = + datasetServiceClient.deleteDatasetAsync(datasetName); + operationFuture.get(); + } + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testImportDataVideoActionRecognitionSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + ImportDataVideoActionRecognitionSample.importDataVideoActionRecognitionSample( + PROJECT, datasetId, GCS_SOURCE_URI); + + // Assert + String got = bout.toString(); + assertThat(got).contains("importDataResponse:"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/ImportDataVideoClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/ImportDataVideoClassificationSampleTest.java new file mode 100644 index 00000000000..53d639f1d64 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/ImportDataVideoClassificationSampleTest.java @@ -0,0 +1,131 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1beta1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.Dataset; +import com.google.cloud.aiplatform.v1beta1.DatasetName; +import com.google.cloud.aiplatform.v1beta1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1beta1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1beta1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.LocationName; +import com.google.protobuf.Empty; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class ImportDataVideoClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String LOCATION = "us-central1"; + private static final String GCS_SOURCE_URI = + "gs://automl-video-demo-data/traffic_videos/traffic_videos_train.csv"; + + private String datasetId; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + + // create a temp dataset for importing data + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/metadata/video_1.0.0.yaml"; + LocationName locationName = LocationName.of(PROJECT, LOCATION); + Dataset dataset = + Dataset.newBuilder() + .setDisplayName("test_dataset_display_name") + .setMetadataSchemaUri(metadataSchemaUri) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + Dataset datasetResponse = datasetFuture.get(300, TimeUnit.SECONDS); + String[] datasetValues = datasetResponse.getName().split("/"); + datasetId = datasetValues[datasetValues.length - 1]; + } + } + + @After + public void tearDown() throws InterruptedException, ExecutionException, IOException { + // delete the temp dataset + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + DatasetName datasetName = DatasetName.of(PROJECT, LOCATION, datasetId); + + OperationFuture operationFuture = + datasetServiceClient.deleteDatasetAsync(datasetName); + operationFuture.get(); + } + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + @Ignore("https://github.com/googleapis/java-aiplatform/issues/420") + public void testImportDataVideoClassificationSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + ImportDataVideoClassificationSample.importDataVideoClassification( + GCS_SOURCE_URI, PROJECT, datasetId); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Import Data Video Classification Response: "); + } +} diff --git a/aiplatform/src/test/java/aiplatform/ImportDataVideoObjectTrackingSampleTest.java b/aiplatform/src/test/java/aiplatform/ImportDataVideoObjectTrackingSampleTest.java new file mode 100644 index 00000000000..4052c91941c --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/ImportDataVideoObjectTrackingSampleTest.java @@ -0,0 +1,130 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import com.google.api.gax.longrunning.OperationFuture; +import com.google.cloud.aiplatform.v1beta1.CreateDatasetOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.Dataset; +import com.google.cloud.aiplatform.v1beta1.DatasetName; +import com.google.cloud.aiplatform.v1beta1.DatasetServiceClient; +import com.google.cloud.aiplatform.v1beta1.DatasetServiceSettings; +import com.google.cloud.aiplatform.v1beta1.DeleteOperationMetadata; +import com.google.cloud.aiplatform.v1beta1.LocationName; +import com.google.protobuf.Empty; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class ImportDataVideoObjectTrackingSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String LOCATION = "us-central1"; + private static final String GCS_SOURCE_URI = + "gs://automl-video-demo-data/traffic_videos/traffic_videos_train.csv"; + private String datasetId; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() + throws InterruptedException, ExecutionException, TimeoutException, IOException { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + + // create a temp dataset for importing data + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + String metadataSchemaUri = + "gs://google-cloud-aiplatform/schema/dataset/metadata/video_1.0.0.yaml"; + LocationName locationName = LocationName.of(PROJECT, LOCATION); + Dataset dataset = + Dataset.newBuilder() + .setDisplayName("test_dataset_display_name") + .setMetadataSchemaUri(metadataSchemaUri) + .build(); + + OperationFuture datasetFuture = + datasetServiceClient.createDatasetAsync(locationName, dataset); + Dataset datasetResponse = datasetFuture.get(300, TimeUnit.SECONDS); + String[] datasetValues = datasetResponse.getName().split("/"); + datasetId = datasetValues[datasetValues.length - 1]; + } + } + + @After + public void tearDown() throws InterruptedException, ExecutionException, IOException { + // delete the temp dataset + if (datasetId != null) { + DatasetServiceSettings datasetServiceSettings = + DatasetServiceSettings.newBuilder() + .setEndpoint("us-central1-aiplatform.googleapis.com:443") + .build(); + try (DatasetServiceClient datasetServiceClient = + DatasetServiceClient.create(datasetServiceSettings)) { + DatasetName datasetName = DatasetName.of(PROJECT, LOCATION, datasetId); + + OperationFuture operationFuture = + datasetServiceClient.deleteDatasetAsync(datasetName); + operationFuture.get(); + } + } + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testImportDataVideoObjectTrackingSample() + throws IOException, InterruptedException, ExecutionException, TimeoutException { + // Act + ImportDataVideoObjectTrackingSample.importDataVideObjectTracking( + GCS_SOURCE_URI, PROJECT, datasetId); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Import Data Video Object Tracking Response: "); + } +} diff --git a/aiplatform/src/test/java/aiplatform/ListModelEvaluationSliceSampleTest.java b/aiplatform/src/test/java/aiplatform/ListModelEvaluationSliceSampleTest.java new file mode 100644 index 00000000000..3ea5f26bc78 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/ListModelEvaluationSliceSampleTest.java @@ -0,0 +1,79 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +@RunWith(JUnit4.class) +public class ListModelEvaluationSliceSampleTest { + + private static final String PROJECT_ID = System.getenv("UCAIP_PROJECT_ID"); + private static final String MODEL_ID = "3512561418744365056"; + private static final String EVALUATION_ID = "9035588644970168320"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testListModelEvaluationSliceSample() throws IOException { + // Act + ListModelEvaluationSliceSample.listModelEvaluationSliceSample( + PROJECT_ID, MODEL_ID, EVALUATION_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains(EVALUATION_ID); + assertThat(got).contains("Model Evaluation Slice Name: "); + } +} diff --git a/aiplatform/src/test/java/aiplatform/PredictCustomTrainedModelSampleTest.java b/aiplatform/src/test/java/aiplatform/PredictCustomTrainedModelSampleTest.java new file mode 100644 index 00000000000..eeeae9766d9 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/PredictCustomTrainedModelSampleTest.java @@ -0,0 +1,82 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import com.google.protobuf.ByteString; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.Base64; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class PredictCustomTrainedModelSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String ENDPOINT_ID = + System.getenv("PREDICT_CUSTOM_TRAINED_MODEL_ENDPOINT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("PREDICT_CUSTOM_TRAINED_MODEL_ENDPOINT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testPredictCustomTrainedModelSample() throws IOException { + // Act + ByteString content = ByteString.copyFrom(Files.readAllBytes(Paths.get("resources/daisy.jpg"))); + String encoded = Base64.getEncoder().encodeToString(content.toByteArray()); + String instance = "[{'image_bytes': {'b64': '" + encoded + "'}, 'key':'0'}]"; + PredictCustomTrainedModelSample.predictCustomTrainedModel(PROJECT, ENDPOINT_ID, instance); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Predict Custom Trained model Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/PredictImageClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/PredictImageClassificationSampleTest.java new file mode 100644 index 00000000000..8ca3fd95c5e --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/PredictImageClassificationSampleTest.java @@ -0,0 +1,75 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class PredictImageClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String FILE_NAME = "resources/image_flower_daisy.jpg"; + private static final String ENDPOINT_ID = System.getenv("IMAGE_CLASS_ENDPOINT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("IMAGE_CLASS_ENDPOINT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testPredictImageClassification() throws IOException { + // Act + PredictImageClassificationSample.predictImageClassification(PROJECT, FILE_NAME, ENDPOINT_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Predict Image Classification Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/PredictImageObjectDetectionSampleTest.java b/aiplatform/src/test/java/aiplatform/PredictImageObjectDetectionSampleTest.java new file mode 100644 index 00000000000..a7d3a16ee8a --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/PredictImageObjectDetectionSampleTest.java @@ -0,0 +1,77 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Ignore; +import org.junit.Test; + +public class PredictImageObjectDetectionSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String FILE_NAME = "resources/iod_caprese_salad.jpg"; + private static final String ENDPOINT_ID = System.getenv("IMAGE_OBJECT_DETECTION_ENDPOINT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("IMAGE_OBJECT_DETECTION_ENDPOINT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Ignore("See https://github.com/googleapis/java-aiplatform/issues/178") + @Test + public void testPredictImageObjectDetection() throws IOException { + // Act + PredictImageObjectDetectionSample.predictImageObjectDetection(PROJECT, FILE_NAME, ENDPOINT_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Predict Image Object Detection Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/PredictTabularClassificationSampleTest.java b/aiplatform/src/test/java/aiplatform/PredictTabularClassificationSampleTest.java new file mode 100644 index 00000000000..25cbf12d5e7 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/PredictTabularClassificationSampleTest.java @@ -0,0 +1,81 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class PredictTabularClassificationSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String INSTANCE = + "[{\"petal_length\": '1.4'," + + " \"petal_width\": '1.3'," + + " \"sepal_length\": '5.1'," + + " \"sepal_width\": '2.8'}]"; + + private static final String ENDPOINT_ID = + System.getenv("PREDICT_TABLES_CLASSIFCATION_ENDPOINT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("PREDICT_TABLES_CLASSIFCATION_ENDPOINT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testPredictTabularClassification() throws IOException { + // Act + PredictTabularClassificationSample.predictTabularClassification(INSTANCE, PROJECT, ENDPOINT_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Predict Tabular Classification Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/PredictTabularRegressionSampleTest.java b/aiplatform/src/test/java/aiplatform/PredictTabularRegressionSampleTest.java new file mode 100644 index 00000000000..44f5bfdfa21 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/PredictTabularRegressionSampleTest.java @@ -0,0 +1,100 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class PredictTabularRegressionSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String INSTANCE = + "[{\n" + + " \"BOOLEAN_2unique_NULLABLE\": False,\n" + + " \"DATETIME_1unique_NULLABLE\": '2019-01-01 00:00:00',\n" + + " \"DATE_1unique_NULLABLE\": '2019-01-01',\n" + + " \"FLOAT_5000unique_NULLABLE\": 1611,\n" + + " \"FLOAT_5000unique_REPEATED\": [2320,1192],\n" + + " \"INTEGER_5000unique_NULLABLE\": '8',\n" + + " \"NUMERIC_5000unique_NULLABLE\": 16,\n" + + " \"STRING_5000unique_NULLABLE\": 'str-2',\n" + + " \"STRUCT_NULLABLE\": {\n" + + " 'BOOLEAN_2unique_NULLABLE': False,\n" + + " 'DATE_1unique_NULLABLE': '2019-01-01',\n" + + " 'DATETIME_1unique_NULLABLE': '2019-01-01 00:00:00',\n" + + " 'FLOAT_5000unique_NULLABLE': 1308,\n" + + " 'FLOAT_5000unique_REPEATED': [2323, 1178],\n" + + " 'FLOAT_5000unique_REQUIRED': 3089,\n" + + " 'INTEGER_5000unique_NULLABLE': '1777',\n" + + " 'NUMERIC_5000unique_NULLABLE': 3323,\n" + + " 'TIME_1unique_NULLABLE': '23:59:59.999999',\n" + + " 'STRING_5000unique_NULLABLE': 'str-49',\n" + + " 'TIMESTAMP_1unique_NULLABLE': '1546387199999999'\n" + + " },\n" + + " \"TIMESTAMP_1unique_NULLABLE\": '1546387199999999',\n" + + " \"TIME_1unique_NULLABLE\": '23:59:59.999999'\n" + + "}]"; + private static final String ENDPOINT_ID = System.getenv("PREDICT_TABLES_REGRESSION_ENDPOINT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("PREDICT_TABLES_REGRESSION_ENDPOINT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testPredictTabularRegression() throws IOException { + // Act + PredictTabularRegressionSample.predictTabularRegression(INSTANCE, PROJECT, ENDPOINT_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Predict Tabular Regression Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/PredictTextClassificationSingleLabelSampleTest.java b/aiplatform/src/test/java/aiplatform/PredictTextClassificationSingleLabelSampleTest.java new file mode 100644 index 00000000000..a47674098a9 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/PredictTextClassificationSingleLabelSampleTest.java @@ -0,0 +1,76 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class PredictTextClassificationSingleLabelSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String TEXT_CONTENT = "This is the test String!"; + private static final String ENDPOINT_ID = System.getenv("TEXT_CLASS_SINGLE_LABEL_ENDPOINT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TEXT_CLASS_SINGLE_LABEL_ENDPOINT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testPredictTextClassification() throws IOException { + // Act + PredictTextClassificationSingleLabelSample.predictTextClassificationSingleLabel( + PROJECT, TEXT_CONTENT, ENDPOINT_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Predict Text Classification Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/PredictTextEntityExtractionSampleTest.java b/aiplatform/src/test/java/aiplatform/PredictTextEntityExtractionSampleTest.java new file mode 100644 index 00000000000..71fd8e8ba26 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/PredictTextEntityExtractionSampleTest.java @@ -0,0 +1,88 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class PredictTextEntityExtractionSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String TEXT_CONTENT = + "1127526\\tAnalbuminemia in a neonate.\\tA small-for-gestational-age infant , found to have" + + " analbuminemia in the neonatal period , is reported and the twelve cases recorded in" + + " the world literature are reviewed . Patients lacking this serum protein are" + + " essentially asymptomatic , apart from minimal ankle edema and ease of fatigue ." + + " Apparent compensatory mechanisms which come into play when serum albumin is low" + + " include prolonged half-life of albumin and transferrin , an increase in serum" + + " globulins , beta lipoprotein , and glycoproteins , arterial hypotension with reduced" + + " capillary hydrostatic pressure , and the ability to respond with rapid sodium and" + + " chloride diuresis in response to small volume changes . Examination of plasma amino" + + " acids , an investigation not previously reported , revealed an extremely low plasma" + + " tryptophan level , a finding which may be important in view of the role of" + + " tryptophan in albumin synthesis."; + private static final String ENDPOINT_ID = System.getenv("TEXT_ENTITY_ENDPOINT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TEXT_ENTITY_ENDPOINT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testPredictTextEntityExtraction() throws IOException { + // Act + PredictTextEntityExtractionSample.predictTextEntityExtraction( + PROJECT, TEXT_CONTENT, ENDPOINT_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Predict Text Entity Extraction Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/PredictTextSentimentAnalysisSampleTest.java b/aiplatform/src/test/java/aiplatform/PredictTextSentimentAnalysisSampleTest.java new file mode 100644 index 00000000000..d452dc94574 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/PredictTextSentimentAnalysisSampleTest.java @@ -0,0 +1,89 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class PredictTextSentimentAnalysisSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String TEXT_CONTENT = + "I was excited at the concept of my favorite comic book hero being on television... and" + + " sorely disappointed at the end result.

The only amazing thing was the" + + " wall crawling (despite the visibility of the cable). I didn't think Nick Hammond was" + + " Peter Parker... and he was visibly of a different build than the guy who did the" + + " stunts in the spider suit. You could tell they were two different actors.
Granted, I can also spot in the modern Spider-Man movies when I am looking at" + + " Tobey Macguire and when I am looking at CGI. But that is from a trained eye and" + + " experience working with CGI. Still, the 70's version could have been better despite" + + " lack of Special FX.

The webs were hokey and looked like ropes that seemed" + + " to wrap around things rather than stick to them. And what was up with giving him a" + + " spider mobile to ride around in. Hello? He's the web slinger people.
Sorry... didn't mean to get so worked up, but our beloved wall crawler deserved" + + " better."; + private static final String ENDPOINT_ID = System.getenv("TEXT_SENTI_ENDPOINT_ID"); + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + requireEnvVar("TEXT_SENTI_ENDPOINT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() { + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void testPredictTextSentimentAnalysis() throws IOException { + // Act + PredictTextSentimentAnalysisSample.predictTextSentimentAnalysis( + PROJECT, TEXT_CONTENT, ENDPOINT_ID); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Predict Text Sentiment Analysis Response"); + } +} diff --git a/aiplatform/src/test/java/aiplatform/UploadModelSampleTest.java b/aiplatform/src/test/java/aiplatform/UploadModelSampleTest.java new file mode 100644 index 00000000000..c085f8c6776 --- /dev/null +++ b/aiplatform/src/test/java/aiplatform/UploadModelSampleTest.java @@ -0,0 +1,98 @@ +/* + * 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. + */ + +package aiplatform; + +import static com.google.common.truth.Truth.assertThat; +import static junit.framework.TestCase.assertNotNull; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; +import java.util.UUID; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +public class UploadModelSampleTest { + + private static final String PROJECT = System.getenv("UCAIP_PROJECT_ID"); + private static final String METADATASCHEMA_URI = ""; + private static final String IMAGE_URI = + "gcr.io/cloud-ml-service-public/" + + "cloud-ml-online-prediction-model-server-cpu:" + + "v1_15py3cmle_op_images_20200229_0210_RC00"; + private static final String ARTIFACT_URI = "gs://ucaip-samples-us-central1/model/explain/"; + private ByteArrayOutputStream bout; + private PrintStream out; + private PrintStream originalPrintStream; + private String uploadedModelId; + + private static void requireEnvVar(String varName) { + String errorMessage = + String.format("Environment variable '%s' is required to perform these tests.", varName); + assertNotNull(errorMessage, System.getenv(varName)); + } + + @BeforeClass + public static void checkRequirements() { + requireEnvVar("GOOGLE_APPLICATION_CREDENTIALS"); + requireEnvVar("UCAIP_PROJECT_ID"); + } + + @Before + public void setUp() { + bout = new ByteArrayOutputStream(); + out = new PrintStream(bout); + originalPrintStream = System.out; + System.setOut(out); + } + + @After + public void tearDown() + throws InterruptedException, ExecutionException, TimeoutException, IOException { + // Cancel the Training Pipeline + DeleteModelSample.deleteModel(PROJECT, uploadedModelId); + + // Assert + String deleteModelResponse = bout.toString(); + assertThat(deleteModelResponse).contains("Deleted Model."); + TimeUnit.MINUTES.sleep(1); + System.out.flush(); + System.setOut(originalPrintStream); + } + + @Test + public void uploadModelSampleTest() + throws InterruptedException, ExecutionException, TimeoutException, IOException { + // Act + String modelDisplayName = + String.format( + "temp_upload_model_test_%s", + UUID.randomUUID().toString().replaceAll("-", "_").substring(0, 26)); + UploadModelSample.uploadModel( + PROJECT, modelDisplayName, METADATASCHEMA_URI, IMAGE_URI, ARTIFACT_URI); + + // Assert + String got = bout.toString(); + assertThat(got).contains("Upload Model Response"); + uploadedModelId = got.split("Model:")[1].split("models/")[1].split("\n")[0]; + } +}

0esPwJ_}D0+E(hu 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�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