diff --git a/conf/db/upgrade/V5.5.22__schema.sql b/conf/db/upgrade/V5.5.22__schema.sql new file mode 100644 index 0000000000..f680641fbd --- /dev/null +++ b/conf/db/upgrade/V5.5.22__schema.sql @@ -0,0 +1,17 @@ +-- ZSTAC-84025: Add pipelineTag to ModelVO for inference template auto-matching +CALL ADD_COLUMN('ModelVO', 'pipelineTag', 'VARCHAR(64)', 1, NULL); + +-- ZSTAC-84025: Add isDefault to ModelServiceRefVO to mark the default inference template per model +ALTER TABLE `zstack`.`ModelServiceRefVO` ADD COLUMN `isDefault` TINYINT(1) NOT NULL DEFAULT 0; + +-- Backfill isDefault: all existing refs default to 0 (no default template designated) +UPDATE `zstack`.`ModelServiceRefVO` SET `isDefault` = 0; + +-- ZSTAC-84025-F2: Add manifestJson to ModelVO so Step 1 (file format) of the auto-match Matcher can +-- parse file_types/file_extensions from the manifest returned by the aios agent. +CALL ADD_COLUMN('ModelVO', 'manifestJson', 'TEXT', 1, NULL); + +-- ZSTAC-84025: Add createDate/lastOpDate to ModelServiceRefVO so the auto-match Matcher can +-- pick the earliest isDefault=true row when DB has the rare 2+ defaults anomaly (Q5). +ALTER TABLE `zstack`.`ModelServiceRefVO` ADD COLUMN `lastOpDate` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP; +ALTER TABLE `zstack`.`ModelServiceRefVO` ADD COLUMN `createDate` TIMESTAMP NOT NULL DEFAULT '0000-00-00 00:00:00'; diff --git a/sdk/src/main/java/org/zstack/sdk/AutoMatchModelServiceByModelAction.java b/sdk/src/main/java/org/zstack/sdk/AutoMatchModelServiceByModelAction.java new file mode 100644 index 0000000000..b9030f9b8c --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/AutoMatchModelServiceByModelAction.java @@ -0,0 +1,101 @@ +package org.zstack.sdk; + +import java.util.HashMap; +import java.util.Map; +import org.zstack.sdk.*; + +public class AutoMatchModelServiceByModelAction extends AbstractAction { + + private static final HashMap parameterMap = new HashMap<>(); + + private static final HashMap nonAPIParameterMap = new HashMap<>(); + + public static class Result { + public ErrorCode error; + public org.zstack.sdk.AutoMatchModelServiceByModelResult value; + + public Result throwExceptionIfError() { + if (error != null) { + throw new ApiException( + String.format("error[code: %s, description: %s, details: %s, globalErrorCode: %s]", error.code, error.description, error.details, error.globalErrorCode) + ); + } + + return this; + } + } + + @Param(required = true, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String modelUuid; + + @Param(required = false) + public java.util.List systemTags; + + @Param(required = false) + public java.util.List userTags; + + @Param(required = false) + public String sessionId; + + @Param(required = false) + public String accessKeyId; + + @Param(required = false) + public String accessKeySecret; + + @Param(required = false) + public String requestIp; + + @NonAPIParam + public long timeout = -1; + + @NonAPIParam + public long pollingInterval = -1; + + + private Result makeResult(ApiResult res) { + Result ret = new Result(); + if (res.error != null) { + ret.error = res.error; + return ret; + } + + org.zstack.sdk.AutoMatchModelServiceByModelResult value = res.getResult(org.zstack.sdk.AutoMatchModelServiceByModelResult.class); + ret.value = value == null ? new org.zstack.sdk.AutoMatchModelServiceByModelResult() : value; + + return ret; + } + + public Result call() { + ApiResult res = ZSClient.call(this); + return makeResult(res); + } + + public void call(final Completion completion) { + ZSClient.call(this, new InternalCompletion() { + @Override + public void complete(ApiResult res) { + completion.complete(makeResult(res)); + } + }); + } + + protected Map getParameterMap() { + return parameterMap; + } + + protected Map getNonAPIParameterMap() { + return nonAPIParameterMap; + } + + protected RestInfo getRestInfo() { + RestInfo info = new RestInfo(); + info.httpMethod = "GET"; + info.path = "/ai/models/{modelUuid}/auto-match-service"; + info.needSession = true; + info.needPoll = false; + info.parameterName = ""; + return info; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/AutoMatchModelServiceByModelResult.java b/sdk/src/main/java/org/zstack/sdk/AutoMatchModelServiceByModelResult.java new file mode 100644 index 0000000000..95393cb6ea --- /dev/null +++ b/sdk/src/main/java/org/zstack/sdk/AutoMatchModelServiceByModelResult.java @@ -0,0 +1,39 @@ +package org.zstack.sdk; + +public class AutoMatchModelServiceByModelResult { + /** + * UUID of the recommended ModelServiceVO. May be null if FALLBACK step + * found no Transformers candidate. + */ + public java.lang.String recommendedServiceUuid; + public void setRecommendedServiceUuid(java.lang.String recommendedServiceUuid) { + this.recommendedServiceUuid = recommendedServiceUuid; + } + public java.lang.String getRecommendedServiceUuid() { + return this.recommendedServiceUuid; + } + + /** + * Which matching step produced this recommendation: + * USER_PRESET | FILE_FORMAT | PIPELINE_TAG | FALLBACK + */ + public java.lang.String matchedByStep; + public void setMatchedByStep(java.lang.String matchedByStep) { + this.matchedByStep = matchedByStep; + } + public java.lang.String getMatchedByStep() { + return this.matchedByStep; + } + + /** + * Diagnostic evidence for the match decision. + */ + public java.util.LinkedHashMap evidence; + public void setEvidence(java.util.LinkedHashMap evidence) { + this.evidence = evidence; + } + public java.util.LinkedHashMap getEvidence() { + return this.evidence; + } + +} diff --git a/sdk/src/main/java/org/zstack/sdk/UpdateModelAction.java b/sdk/src/main/java/org/zstack/sdk/UpdateModelAction.java index 3b27ed271d..f7936631ad 100644 --- a/sdk/src/main/java/org/zstack/sdk/UpdateModelAction.java +++ b/sdk/src/main/java/org/zstack/sdk/UpdateModelAction.java @@ -58,6 +58,9 @@ public Result throwExceptionIfError() { @Param(required = false, maxLength = 255, nonempty = false, nullElements = false, emptyString = true, noTrim = false) public java.lang.String modelId; + @Param(required = false, nonempty = false, nullElements = false, emptyString = true, noTrim = false) + public java.lang.String defaultModelServiceUuid; + @Param(required = false) public java.util.List systemTags; diff --git a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy index ab4531b5ad..b505a26786 100644 --- a/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy +++ b/testlib/src/main/java/org/zstack/testlib/ApiHelper.groovy @@ -4769,6 +4769,33 @@ abstract class ApiHelper { } + def autoMatchModelServiceByModel(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.AutoMatchModelServiceByModelAction.class) Closure c) { + def a = new org.zstack.sdk.AutoMatchModelServiceByModelAction() + a.sessionId = Test.currentEnvSpec?.session?.uuid + c.resolveStrategy = Closure.OWNER_FIRST + c.delegate = a + c() + + + if (System.getProperty("apipath") != null) { + if (a.apiId == null) { + a.apiId = Platform.uuid + } + + def tracker = new ApiPathTracker(a.apiId) + def out = errorOut(a.call()) + def path = tracker.getApiPath() + if (!path.isEmpty()) { + Test.apiPaths[a.class.name] = path.join(" --->\n") + } + + return out + } else { + return errorOut(a.call()) + } + } + + def backupDatabaseToPublicCloud(@DelegatesTo(strategy = Closure.OWNER_FIRST, value = org.zstack.sdk.BackupDatabaseToPublicCloudAction.class) Closure c) { def a = new org.zstack.sdk.BackupDatabaseToPublicCloudAction() a.sessionId = Test.currentEnvSpec?.session?.uuid