Skip to content

Commit a33a51a

Browse files
authored
Merge pull request #56 from comet-ml/CM-2348-get-registry-model-details
[CM-2348]: Implement equivalent of API.get_registry_model_details
2 parents b818b77 + f067ae5 commit a33a51a

File tree

12 files changed

+437
-4
lines changed

12 files changed

+437
-4
lines changed

comet-examples/src/main/java/ml/comet/examples/RegistryModelExample.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import ml.comet.experiment.registrymodel.DownloadModelOptions;
1010
import ml.comet.experiment.registrymodel.Model;
1111
import ml.comet.experiment.registrymodel.ModelDownloadInfo;
12+
import ml.comet.experiment.registrymodel.ModelOverview;
1213
import ml.comet.experiment.registrymodel.ModelRegistryRecord;
14+
import ml.comet.experiment.registrymodel.ModelVersionOverview;
1315
import org.apache.commons.io.file.PathUtils;
1416
import org.awaitility.Awaitility;
1517

@@ -18,6 +20,7 @@
1820
import java.util.Collections;
1921
import java.util.List;
2022
import java.util.Map;
23+
import java.util.Optional;
2124
import java.util.concurrent.TimeUnit;
2225

2326
import static ml.comet.examples.LogModelExample.SOME_MODEL_NAME;
@@ -129,6 +132,36 @@ record = api.registerModel(updatedModel, experiment.getExperimentKey());
129132
System.out.printf("Successfully downloaded model's file assets as ZIP file '%s'.\n\n",
130133
info.getDownloadPath());
131134

135+
// get model's overview
136+
//
137+
System.out.printf("Retrieving overview details of the model '%s'\n", registryName);
138+
Optional<ModelOverview> modelOverviewOptional = api.getRegistryModelDetails(
139+
registryName, experiment.getWorkspaceName());
140+
if (modelOverviewOptional.isPresent()) {
141+
ModelOverview modelOverview = modelOverviewOptional.get();
142+
System.out.printf(
143+
"Retrieved overview details of the model '%s' which was created at '%s' and has %d versions.\n",
144+
registryName, modelOverview.getCreatedAt(), modelOverview.getVersions().size());
145+
} else {
146+
System.out.printf("Overview of the model '%s' not found\n", registryName);
147+
}
148+
149+
// get details about model version
150+
//
151+
System.out.printf("Retrieving details of the model version '%s:%s'\n", registryName, SOME_MODEL_VERSION_UP);
152+
Optional<ModelVersionOverview> versionOverviewOptional = api.getRegistryModelVersion(
153+
registryName, experiment.getWorkspaceName(), SOME_MODEL_VERSION_UP);
154+
if (versionOverviewOptional.isPresent()) {
155+
ModelVersionOverview versionOverview = versionOverviewOptional.get();
156+
System.out.printf(
157+
"Retrieved overview of the model version '%s:%s' which was created at '%s' with stages '%s'.\n",
158+
registryName, versionOverview.getVersion(), versionOverview.getCreatedAt(),
159+
versionOverview.getStages());
160+
} else {
161+
System.out.printf("Overview of the model version '%s:%s' not found\n",
162+
registryName, SOME_MODEL_VERSION_UP);
163+
}
164+
132165
} finally {
133166
PathUtils.deleteDirectory(modelTmpDir);
134167
}

comet-java-client/src/main/java/ml/comet/experiment/CometApi.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
22

33
import ml.comet.experiment.model.ExperimentMetadata;
44
import ml.comet.experiment.model.Project;
5-
import ml.comet.experiment.registrymodel.ModelDownloadInfo;
65
import ml.comet.experiment.registrymodel.DownloadModelOptions;
76
import ml.comet.experiment.registrymodel.Model;
7+
import ml.comet.experiment.registrymodel.ModelDownloadInfo;
8+
import ml.comet.experiment.registrymodel.ModelOverview;
89
import ml.comet.experiment.registrymodel.ModelRegistryRecord;
10+
import ml.comet.experiment.registrymodel.ModelVersionOverview;
911

1012
import java.io.Closeable;
1113
import java.io.IOException;
1214
import java.nio.file.Path;
1315
import java.util.List;
16+
import java.util.Optional;
1417

1518
/**
1619
* The utility providing direct access to the Comet REST API.
@@ -65,4 +68,23 @@ ModelDownloadInfo downloadRegistryModel(Path outputPath, String registryName, St
6568
DownloadModelOptions options) throws IOException;
6669

6770
ModelDownloadInfo downloadRegistryModel(Path outputPath, String registryName, String workspace) throws IOException;
71+
72+
/**
73+
* Allows querying for details about specific registry model.
74+
*
75+
* @param registryName the name of the model as in models' registry.
76+
* @param workspace the name of the model's workspace.
77+
* @return the optional {@link ModelOverview} with model version details.
78+
*/
79+
Optional<ModelOverview> getRegistryModelDetails(String registryName, String workspace);
80+
81+
/**
82+
* Allows querying for details about specific version of the registry model.
83+
*
84+
* @param registryName the name of the model as in models' registry.
85+
* @param workspace the name of the model's workspace.
86+
* @param version the version of the registry model to be returned.
87+
* @return the optional {@link ModelOverview} with model version details.
88+
*/
89+
Optional<ModelVersionOverview> getRegistryModelVersion(String registryName, String workspace, String version);
6890
}

comet-java-client/src/main/java/ml/comet/experiment/impl/CometApiImpl.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import ml.comet.experiment.impl.rest.ExperimentModelListResponse;
1414
import ml.comet.experiment.impl.rest.ExperimentModelResponse;
1515
import ml.comet.experiment.impl.rest.RegistryModelCreateRequest;
16+
import ml.comet.experiment.impl.rest.RegistryModelDetailsResponse;
1617
import ml.comet.experiment.impl.rest.RegistryModelItemCreateRequest;
1718
import ml.comet.experiment.impl.rest.RegistryModelOverviewListResponse;
1819
import ml.comet.experiment.impl.rest.RestApiResponse;
@@ -22,11 +23,13 @@
2223
import ml.comet.experiment.impl.utils.ZipUtils;
2324
import ml.comet.experiment.model.ExperimentMetadata;
2425
import ml.comet.experiment.model.Project;
25-
import ml.comet.experiment.registrymodel.ModelDownloadInfo;
2626
import ml.comet.experiment.registrymodel.DownloadModelOptions;
2727
import ml.comet.experiment.registrymodel.Model;
28+
import ml.comet.experiment.registrymodel.ModelDownloadInfo;
2829
import ml.comet.experiment.registrymodel.ModelNotFoundException;
30+
import ml.comet.experiment.registrymodel.ModelOverview;
2931
import ml.comet.experiment.registrymodel.ModelRegistryRecord;
32+
import ml.comet.experiment.registrymodel.ModelVersionOverview;
3033
import org.apache.commons.lang3.StringUtils;
3134
import org.slf4j.Logger;
3235
import org.slf4j.LoggerFactory;
@@ -56,6 +59,8 @@
5659
import static ml.comet.experiment.impl.resources.LogMessages.EXTRACTED_N_REGISTRY_MODEL_FILES;
5760
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_DOWNLOAD_REGISTRY_MODEL;
5861
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_FIND_EXPERIMENT_MODEL_BY_NAME;
62+
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_GET_REGISTRY_MODEL_DETAILS;
63+
import static ml.comet.experiment.impl.resources.LogMessages.FAILED_TO_GET_REGISTRY_MODEL_VERSIONS;
5964
import static ml.comet.experiment.impl.resources.LogMessages.MODEL_REGISTERED_IN_WORKSPACE;
6065
import static ml.comet.experiment.impl.resources.LogMessages.MODEL_VERSION_CREATED_IN_WORKSPACE;
6166
import static ml.comet.experiment.impl.resources.LogMessages.UPDATE_REGISTRY_MODEL_DESCRIPTION_IGNORED;
@@ -227,6 +232,41 @@ public ModelDownloadInfo downloadRegistryModel(@NonNull Path outputPath, @NonNul
227232
return this.downloadRegistryModel(outputPath, registryName, workspace, DownloadModelOptions.Op().build());
228233
}
229234

235+
@Override
236+
public Optional<ModelOverview> getRegistryModelDetails(@NonNull String registryName, @NonNull String workspace) {
237+
try {
238+
RegistryModelDetailsResponse details = this.restApiClient.getRegistryModelDetails(registryName, workspace)
239+
.blockingGet();
240+
return Optional.of(details.toModelOverview(this.logger));
241+
} catch (CometApiException ex) {
242+
this.logger.error(getString(FAILED_TO_GET_REGISTRY_MODEL_DETAILS,
243+
workspace, registryName, ex.getStatusMessage(), ex.getSdkErrorCode()), ex);
244+
if (ex.getSdkErrorCode() == 42008) {
245+
return Optional.empty();
246+
}
247+
throw ex;
248+
}
249+
}
250+
251+
@Override
252+
public Optional<ModelVersionOverview> getRegistryModelVersion(
253+
@NonNull String registryName, @NonNull String workspace, @NonNull String version) {
254+
Optional<ModelOverview> overviewOptional = this.getRegistryModelDetails(registryName, workspace);
255+
if (!overviewOptional.isPresent()) {
256+
return Optional.empty();
257+
}
258+
ModelOverview overview = overviewOptional.get();
259+
if (overview.getVersions() == null || overview.getVersions().size() == 0) {
260+
String msg = getString(FAILED_TO_GET_REGISTRY_MODEL_VERSIONS, workspace, registryName);
261+
this.logger.error(msg);
262+
throw new ModelNotFoundException(msg);
263+
}
264+
return overview.getVersions()
265+
.stream()
266+
.filter(versionOverview -> Objects.equals(versionOverview.getVersion(), version))
267+
.findFirst();
268+
}
269+
230270
/**
231271
* Release all resources hold by this instance, such as connection to the Comet server.
232272
*

comet-java-client/src/main/java/ml/comet/experiment/impl/RestApiClient.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import ml.comet.experiment.impl.rest.ParameterRest;
4444
import ml.comet.experiment.impl.rest.RegistryModelCreateRequest;
4545
import ml.comet.experiment.impl.rest.RegistryModelCreateResponse;
46+
import ml.comet.experiment.impl.rest.RegistryModelDetailsResponse;
4647
import ml.comet.experiment.impl.rest.RegistryModelItemCreateRequest;
4748
import ml.comet.experiment.impl.rest.RegistryModelItemCreateResponse;
4849
import ml.comet.experiment.impl.rest.RegistryModelOverviewListResponse;
@@ -87,6 +88,7 @@
8788
import static ml.comet.experiment.impl.constants.ApiEndpoints.GET_METRICS;
8889
import static ml.comet.experiment.impl.constants.ApiEndpoints.GET_OUTPUT;
8990
import static ml.comet.experiment.impl.constants.ApiEndpoints.GET_PARAMETERS;
91+
import static ml.comet.experiment.impl.constants.ApiEndpoints.GET_REGISTRY_MODEL_DETAILS;
9092
import static ml.comet.experiment.impl.constants.ApiEndpoints.GET_REGISTRY_MODEL_LIST;
9193
import static ml.comet.experiment.impl.constants.ApiEndpoints.GET_TAGS;
9294
import static ml.comet.experiment.impl.constants.ApiEndpoints.NEW_EXPERIMENT;
@@ -100,6 +102,7 @@
100102
import static ml.comet.experiment.impl.constants.QueryParamName.ARTIFACT_VERSION_ID;
101103
import static ml.comet.experiment.impl.constants.QueryParamName.EXPERIMENT_KEY;
102104
import static ml.comet.experiment.impl.constants.QueryParamName.IS_REMOTE;
105+
import static ml.comet.experiment.impl.constants.QueryParamName.MODEL_NAME;
103106
import static ml.comet.experiment.impl.constants.QueryParamName.PROJECT_ID;
104107
import static ml.comet.experiment.impl.constants.QueryParamName.TYPE;
105108
import static ml.comet.experiment.impl.constants.QueryParamName.WORKSPACE_NAME;
@@ -340,6 +343,14 @@ Single<RegistryModelItemCreateResponse> createRegistryModelItem(final RegistryMo
340343
RegistryModelItemCreateResponse.class);
341344
}
342345

346+
Single<RegistryModelDetailsResponse> getRegistryModelDetails(String modelName, String workspaceName) {
347+
Map<QueryParamName, String> queryParams = new HashMap<>();
348+
queryParams.put(WORKSPACE_NAME, workspaceName);
349+
queryParams.put(MODEL_NAME, modelName);
350+
return singleFromSyncGetWithRetries(GET_REGISTRY_MODEL_DETAILS, queryParams, true,
351+
RegistryModelDetailsResponse.class);
352+
}
353+
343354
Single<RestApiResponse> downloadRegistryModel(
344355
final OutputStream output, String workspace, String registryName, final DownloadModelOptions options) {
345356
Map<QueryParamName, String> queryParams = downloadModelParams(workspace, registryName, options);

comet-java-client/src/main/java/ml/comet/experiment/impl/constants/ApiEndpoints.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,5 @@ public final class ApiEndpoints {
4646
public static final String GET_EXPERIMENT_MODEL_LIST = READ_API_URL + "/experiment/model";
4747
public static final String GET_REGISTRY_MODEL_LIST = READ_API_URL + "/registry-model";
4848
public static final String DOWNLOAD_REGISTRY_MODEL = READ_API_URL + "/registry-model/item/download";
49+
public static final String GET_REGISTRY_MODEL_DETAILS = READ_API_URL + "/registry-model/details";
4950
}

comet-java-client/src/main/java/ml/comet/experiment/impl/resources/LogMessages.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ public class LogMessages {
8888
public static final String INVALID_MODEL_REGISTRY_NAME_PROVIDED = "INVALID_MODEL_REGISTRY_NAME_PROVIDED";
8989
public static final String VERSION_AND_STAGE_SET_DOWNLOAD_MODEL = "VERSION_AND_STAGE_SET_DOWNLOAD_MODEL";
9090
public static final String FAILED_TO_DOWNLOAD_REGISTRY_MODEL = "FAILED_TO_DOWNLOAD_REGISTRY_MODEL";
91+
public static final String FAILED_TO_GET_REGISTRY_MODEL_DETAILS = "FAILED_TO_GET_REGISTRY_MODEL_DETAILS";
92+
public static final String FAILED_TO_GET_REGISTRY_MODEL_VERSIONS = "FAILED_TO_GET_REGISTRY_MODEL_VERSIONS";
9193

9294

9395
/**
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package ml.comet.experiment.impl.rest;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import com.fasterxml.jackson.annotation.JsonInclude;
5+
import com.fasterxml.jackson.annotation.JsonProperty;
6+
import lombok.AllArgsConstructor;
7+
import lombok.Data;
8+
import lombok.NoArgsConstructor;
9+
import ml.comet.experiment.registrymodel.ModelOverview;
10+
import ml.comet.experiment.registrymodel.ModelVersionOverview;
11+
import org.slf4j.Logger;
12+
13+
import java.time.Instant;
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
17+
@JsonIgnoreProperties(ignoreUnknown = true)
18+
@JsonInclude(JsonInclude.Include.NON_NULL)
19+
@NoArgsConstructor
20+
@AllArgsConstructor
21+
@Data
22+
public class RegistryModelDetailsResponse {
23+
private String registryModelId;
24+
private String workspaceId;
25+
private String modelName;
26+
private String description;
27+
private long numberOfVersions;
28+
@JsonProperty("isPublic")
29+
private boolean isPublic;
30+
private boolean isAutoGenerated;
31+
private boolean isMonitored;
32+
private List<RegistryModelItemDetails> versions;
33+
private String imagePath;
34+
private String userName;
35+
private long createdAt;
36+
private long lastUpdated;
37+
38+
/**
39+
* Converts this to {@link ModelOverview} exposed by public API.
40+
*
41+
* @param logger the logger to be used for output.
42+
* @return the initialized instance of the {@link ModelOverview}.
43+
*/
44+
public ModelOverview toModelOverview(Logger logger) {
45+
ModelOverview model = new ModelOverview();
46+
model.setRegistryModelId(this.registryModelId);
47+
model.setWorkspaceId(this.workspaceId);
48+
model.setModelName(this.modelName);
49+
model.setDescription(this.description);
50+
model.setNumberOfVersions(this.numberOfVersions);
51+
model.setPublic(this.isPublic);
52+
model.setUserName(this.userName);
53+
if (this.createdAt > 0) {
54+
model.setCreatedAt(Instant.ofEpochMilli(this.createdAt));
55+
}
56+
if (this.lastUpdated > 0) {
57+
model.setLastUpdated(Instant.ofEpochMilli(this.lastUpdated));
58+
}
59+
if (this.versions != null) {
60+
List<ModelVersionOverview> versions = this.versions
61+
.stream()
62+
.collect(ArrayList::new,
63+
(versionOverviews, modelItemDetails) -> versionOverviews.add(
64+
modelItemDetails.toModelVersionOverview(logger)),
65+
ArrayList::addAll);
66+
model.setVersions(versions);
67+
}
68+
return model;
69+
}
70+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
package ml.comet.experiment.impl.rest;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
import com.fasterxml.jackson.annotation.JsonInclude;
5+
import lombok.AllArgsConstructor;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
import ml.comet.experiment.asset.LoggedExperimentAsset;
9+
import ml.comet.experiment.registrymodel.ModelVersionOverview;
10+
import org.slf4j.Logger;
11+
12+
import java.time.Instant;
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
16+
@Data
17+
@NoArgsConstructor
18+
@AllArgsConstructor
19+
@JsonIgnoreProperties(ignoreUnknown = true)
20+
@JsonInclude(JsonInclude.Include.NON_NULL)
21+
public class RegistryModelItemDetails {
22+
private String registryModelItemId;
23+
private ExperimentModelResponse experimentModel;
24+
private String version;
25+
private String comment;
26+
private List<String> stages;
27+
private List<ExperimentAssetLink> assets;
28+
private String userName;
29+
private long createdAt;
30+
private long lastUpdated;
31+
private String restApiUrl;
32+
33+
/**
34+
* Converts this into {@link ModelVersionOverview}.
35+
*
36+
* @param logger the logger to be used for output.
37+
* @return the initialized {@link ModelVersionOverview} instance.
38+
*/
39+
public ModelVersionOverview toModelVersionOverview(Logger logger) {
40+
ModelVersionOverview model = new ModelVersionOverview();
41+
model.setRegistryModelItemId(this.registryModelItemId);
42+
model.setVersion(this.version);
43+
model.setComment(this.comment);
44+
model.setStages(this.stages);
45+
model.setUserName(this.userName);
46+
model.setRestApiUrl(this.restApiUrl);
47+
if (this.createdAt > 0) {
48+
model.setCreatedAt(Instant.ofEpochMilli(this.createdAt));
49+
}
50+
if (this.lastUpdated > 0) {
51+
model.setLastUpdated(Instant.ofEpochMilli(this.lastUpdated));
52+
}
53+
if (this.assets != null) {
54+
ArrayList<LoggedExperimentAsset> loggedAssets = this.assets
55+
.stream().collect(
56+
ArrayList::new,
57+
(experimentAssets, assetLink) -> experimentAssets.add(assetLink.toExperimentAsset(logger)),
58+
ArrayList::addAll);
59+
model.setAssets(loggedAssets);
60+
}
61+
return model;
62+
}
63+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package ml.comet.experiment.registrymodel;
2+
3+
import lombok.Data;
4+
5+
import java.time.Instant;
6+
import java.util.List;
7+
8+
/**
9+
* Holds overview of particular registry model which was retrieved from Comet server.
10+
*/
11+
@Data
12+
public class ModelOverview {
13+
private String registryModelId;
14+
private String workspaceId;
15+
private String modelName;
16+
private String description;
17+
private long numberOfVersions;
18+
private boolean isPublic;
19+
private String userName;
20+
private List<ModelVersionOverview> versions;
21+
private Instant createdAt;
22+
private Instant lastUpdated;
23+
}

0 commit comments

Comments
 (0)