diff --git a/specification/cognitiveservices/ContentSafety/models.tsp b/specification/cognitiveservices/ContentSafety/models.tsp index 6459f69d9e01..b77017314c13 100644 --- a/specification/cognitiveservices/ContentSafety/models.tsp +++ b/specification/cognitiveservices/ContentSafety/models.tsp @@ -40,6 +40,14 @@ enum AnalyzeImageOutputType { FourSeverityLevels, } +@added(ContentSafety.Versions.v2024_01_30_Preview) +enum ModelStatus { + created, + training, + ready, + failed, +} + @doc("The text analysis request.") model AnalyzeTextOptions { @doc("The text needs to be analyzed. We support a maximum of 10k Unicode characters (Unicode code points) in the text of one request.") @@ -61,6 +69,20 @@ model AnalyzeTextOptions { @added(ContentSafety.Versions.v2023_10_30_Preview) @doc("The incidents to detect.") incidents?: IncidentOptions; + + @added(ContentSafety.Versions.v2024_01_30_Preview) + @doc("The customized categories will be analyzed. If they are not assigned, the analysis results for all available customized categories will be returned.") + customizedCategories?: CustomizedCategory[]; +} + +@added(ContentSafety.Versions.v2024_01_30_Preview) +@doc("Customized category for inference.") +model CustomizedCategory { + @doc("Category name") + categoryName: string; + + @doc("Model ID for the category. If not provided, the latest available model will be used.") + modelId: string; } @added(ContentSafety.Versions.v2023_10_30_Preview) @@ -88,6 +110,28 @@ model AnalyzeTextResult { @added(ContentSafety.Versions.v2024_01_30_Preview) @doc("Chunks in the original text detected as harmful content. Analysis result and scores are caused by these.") citation?: string[]; + + @added(ContentSafety.Versions.v2024_01_30_Preview) + @doc("Analysis result for customized categories.") + customizedCategoriesAnalysis: TextCustomizedCategoryAnalysis[]; +} + +@added(ContentSafety.Versions.v2024_01_30_Preview) +@doc("Text customized category analysis result.") +model TextCustomizedCategoryAnalysis { + @doc("Customized category name") + categoryName: string; + + @doc("customized category analysis") + customizedCategoriesAnalysis: TextCustomizedCategoryClassResult[]; +} + +@added(ContentSafety.Versions.v2024_01_30_Preview) +@doc("customized category analysis result") +model TextCustomizedCategoryClassResult { + id: int32; + @renamedFrom(Versions.v2024_01_30_Preview, "name") + className: string; } @doc("The result of blocklist match.") @@ -456,9 +500,11 @@ model PreDefinedConcept { @added(Versions.v2023_10_30_Preview) @doc("Label definition.") -model SubCategory { +@renamedFrom(Versions.v2024_01_30_Preview, "SubCategory") +model Class { id: int32; - name: string; + @renamedFrom(Versions.v2024_01_30_Preview, "name") + className: string; statements: string[]; } @@ -473,12 +519,39 @@ model TextCustomizedCategory { @maxLength(64) categoryName: string; + @doc("A predefined concept with its definition can be used directly in the subcategories.") + @added(Versions.v2023_10_30_Preview) + @removed(Versions.v2024_01_30_Preview) preDefinedConcepts?: PreDefinedConcept[]; - subCategories: SubCategory[]; + + @doc("Subcategories are detailed classes of the category. It is required there is a class 'safe' with id=0.") + @renamedFrom(Versions.v2024_01_30_Preview, "subCategories") + classes: Class[]; + + @added(Versions.v2023_10_30_Preview) + @removed(Versions.v2024_01_30_Preview) emphases?: string[]; + + @doc("Blob that stores the examples.") exampleBlobUrl?: url; } +@added(ContentSafety.Versions.v2024_01_30_Preview) +@doc("The response for async training triggering.") +model SubmitModelTrainingResponse { + ...AcceptedResponse; + + @header("operation-location") + @doc("The location of the status API for monitoring the triggered model.") + modelUrl: string; +} + +@added(ContentSafety.Versions.v2024_01_30_Preview) +model AsyncJobWarning { + code: string; + messgae: string; +} + #suppress "@azure-tools/typespec-azure-core/documentation-required" "MUST fix in next update" @added(ContentSafety.Versions.v2023_10_30_Preview) @doc("ImageWithText analyze category.") @@ -489,6 +562,19 @@ enum ImageWithTextCategory { Violence, } +@added(ContentSafety.Versions.v2024_01_30_Preview) +@parentResource(TextCustomizedCategory) +@resource("models") +model TextTrainedModel { + @key + modelId: string; + status: ModelStatus; + createdTime: utcDateTime; + lastUpdateTime: utcDateTime; + warnings?: AsyncJobWarning[]; + errors?: string[]; +} + @added(ContentSafety.Versions.v2023_10_30_Preview) @doc("The analysis request of the image with text.") model AnalyzeImageWithTextOptions { diff --git a/specification/cognitiveservices/ContentSafety/routes.tsp b/specification/cognitiveservices/ContentSafety/routes.tsp index 6e0b436297b0..16b36381a21a 100644 --- a/specification/cognitiveservices/ContentSafety/routes.tsp +++ b/specification/cognitiveservices/ContentSafety/routes.tsp @@ -290,6 +290,37 @@ interface TextCategoryCustomization { TextCustomizedCategory, ListQueryParametersTrait >; + + @action("trainModel") + @added(Versions.v2024_01_30_Preview) + trainModel is CategoryOps.ResourceAction< + TextCustomizedCategory, + {}, + SubmitModelTrainingResponse + >; +} + +interface TextCustomizedMdoelOps + extends Azure.Core.ResourceOperations {} + +@added(Versions.v2024_01_30_Preview) +interface TextCustomizedModelOperations { + @summary("List all existing models") + @doc("List existing models.") + listTextCustomizedModels is TextCustomizedMdoelOps.ResourceList< + TextTrainedModel, + ListQueryParametersTrait + >; + + @doc("Get a model that is not deleted.") + getTextCustomizedModels is TextCustomizedMdoelOps.ResourceRead; + + @doc("If the model is training, the training process will be cancelled and the model will also be deleted.") + deleteCustomizedModel is TextCustomizedMdoelOps.ResourceDelete< + TextTrainedModel + >; } @added(Versions.v2023_10_30_Preview) diff --git a/specification/cognitiveservices/data-plane/ContentSafety/preview/2023-10-30-preview/contentsafety.json b/specification/cognitiveservices/data-plane/ContentSafety/preview/2023-10-30-preview/contentsafety.json index f4f32e3af776..9d0aad9dfe01 100644 --- a/specification/cognitiveservices/data-plane/ContentSafety/preview/2023-10-30-preview/contentsafety.json +++ b/specification/cognitiveservices/data-plane/ContentSafety/preview/2023-10-30-preview/contentsafety.json @@ -2931,6 +2931,7 @@ }, "preDefinedConcepts": { "type": "array", + "description": "A predefined concept with its definition can be used directly in the subcategories.", "items": { "$ref": "#/definitions/PreDefinedConcept" }, @@ -2938,6 +2939,7 @@ }, "subCategories": { "type": "array", + "description": "Subcategories are detailed classes of the category. It is required there is a class 'safe' with id=0.", "items": { "$ref": "#/definitions/SubCategory" } @@ -2950,7 +2952,8 @@ }, "exampleBlobUrl": { "type": "string", - "format": "uri" + "format": "uri", + "description": "Blob that stores the examples." } }, "required": [ diff --git a/specification/cognitiveservices/data-plane/ContentSafety/preview/2024-01-30-preview/contentsafety.json b/specification/cognitiveservices/data-plane/ContentSafety/preview/2024-01-30-preview/contentsafety.json index 208f36065325..f1efad653ecf 100644 --- a/specification/cognitiveservices/data-plane/ContentSafety/preview/2024-01-30-preview/contentsafety.json +++ b/specification/cognitiveservices/data-plane/ContentSafety/preview/2024-01-30-preview/contentsafety.json @@ -1055,6 +1055,189 @@ } } }, + "/text/categories/{categoryName}:trainModel": { + "post": { + "operationId": "TextCategoryCustomization_TrainModel", + "description": "Resource action operation template.", + "parameters": [ + { + "$ref": "#/parameters/Azure.Core.Foundations.ApiVersionParameter" + }, + { + "name": "categoryName", + "in": "path", + "description": "Text customizedCategories name.", + "required": true, + "type": "string", + "maxLength": 64, + "pattern": "^Customized_[0-9A-Za-z._~-]+$" + } + ], + "responses": { + "202": { + "description": "The request has been accepted for processing, but processing has not yet completed.", + "headers": { + "operation-location": { + "type": "string", + "description": "The location of the status API for monitoring the triggered model." + } + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/Azure.Core.Foundations.ErrorResponse" + }, + "headers": { + "x-ms-error-code": { + "type": "string", + "description": "String error code indicating what went wrong." + } + } + } + } + } + }, + "/text/categories/{categoryName}/models": { + "get": { + "operationId": "TextCustomizedModelOperations_ListTextCustomizedModels", + "summary": "List all existing models", + "description": "List existing models.", + "parameters": [ + { + "$ref": "#/parameters/Azure.Core.Foundations.ApiVersionParameter" + }, + { + "name": "categoryName", + "in": "path", + "description": "Text customizedCategories name.", + "required": true, + "type": "string", + "maxLength": 64, + "pattern": "^Customized_[0-9A-Za-z._~-]+$" + }, + { + "$ref": "#/parameters/Azure.Core.TopQueryParameter" + }, + { + "$ref": "#/parameters/Azure.Core.SkipQueryParameter" + }, + { + "$ref": "#/parameters/Azure.Core.MaxPageSizeQueryParameter" + } + ], + "responses": { + "200": { + "description": "The request has succeeded.", + "schema": { + "$ref": "#/definitions/PagedTextTrainedModel" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/Azure.Core.Foundations.ErrorResponse" + }, + "headers": { + "x-ms-error-code": { + "type": "string", + "description": "String error code indicating what went wrong." + } + } + } + }, + "x-ms-pageable": { + "nextLinkName": "nextLink" + } + } + }, + "/text/categories/{categoryName}/models/{modelId}": { + "get": { + "operationId": "TextCustomizedModelOperations_GetTextCustomizedModels", + "description": "Get a model that is not deleted.", + "parameters": [ + { + "$ref": "#/parameters/Azure.Core.Foundations.ApiVersionParameter" + }, + { + "name": "categoryName", + "in": "path", + "description": "Text customizedCategories name.", + "required": true, + "type": "string", + "maxLength": 64, + "pattern": "^Customized_[0-9A-Za-z._~-]+$" + }, + { + "name": "modelId", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "200": { + "description": "The request has succeeded.", + "schema": { + "$ref": "#/definitions/TextTrainedModel" + } + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/Azure.Core.Foundations.ErrorResponse" + }, + "headers": { + "x-ms-error-code": { + "type": "string", + "description": "String error code indicating what went wrong." + } + } + } + } + }, + "delete": { + "operationId": "TextCustomizedModelOperations_DeleteCustomizedModel", + "description": "If the model is training, the training process will be cancelled and the model will also be deleted.", + "parameters": [ + { + "$ref": "#/parameters/Azure.Core.Foundations.ApiVersionParameter" + }, + { + "name": "categoryName", + "in": "path", + "description": "Text customizedCategories name.", + "required": true, + "type": "string", + "maxLength": 64, + "pattern": "^Customized_[0-9A-Za-z._~-]+$" + }, + { + "name": "modelId", + "in": "path", + "required": true, + "type": "string" + } + ], + "responses": { + "204": { + "description": "There is no content to send for this request, but the headers may be useful. " + }, + "default": { + "description": "An unexpected error response.", + "schema": { + "$ref": "#/definitions/Azure.Core.Foundations.ErrorResponse" + }, + "headers": { + "x-ms-error-code": { + "type": "string", + "description": "String error code indicating what went wrong." + } + } + } + } + } + }, "/text/incidents": { "get": { "operationId": "TextIncidents_ListIncidents", @@ -1920,6 +2103,14 @@ "incidents": { "$ref": "#/definitions/IncidentOptions", "description": "The incidents to detect." + }, + "customizedCategories": { + "type": "array", + "description": "The customized categories will be analyzed. If they are not assigned, the analysis results for all available customized categories will be returned.", + "items": { + "$ref": "#/definitions/CustomizedCategory" + }, + "x-ms-identifiers": [] } }, "required": [ @@ -2011,10 +2202,19 @@ "items": { "type": "string" } + }, + "customizedCategoriesAnalysis": { + "type": "array", + "description": "Analysis result for customized categories.", + "items": { + "$ref": "#/definitions/TextCustomizedCategoryAnalysis" + }, + "x-ms-identifiers": [] } }, "required": [ - "categoriesAnalysis" + "categoriesAnalysis", + "customizedCategoriesAnalysis" ] }, "AnnotateTextOptions": { @@ -2059,6 +2259,21 @@ "name" ] }, + "AsyncJobWarning": { + "type": "object", + "properties": { + "code": { + "type": "string" + }, + "messgae": { + "type": "string" + } + }, + "required": [ + "code", + "messgae" + ] + }, "Azure.Core.Foundations.Error": { "type": "object", "description": "The error object.", @@ -2120,6 +2335,48 @@ } } }, + "Class": { + "type": "object", + "description": "Label definition.", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "className": { + "type": "string" + }, + "statements": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "id", + "className", + "statements" + ] + }, + "CustomizedCategory": { + "type": "object", + "description": "Customized category for inference.", + "properties": { + "categoryName": { + "type": "string", + "description": "Category name" + }, + "modelId": { + "type": "string", + "description": "Model ID for the category. If not provided, the latest available model will be used." + } + }, + "required": [ + "categoryName", + "modelId" + ] + }, "DetectUngroundednessOptions": { "type": "object", "description": "The request of ungroundedness detection.", @@ -2476,6 +2733,19 @@ "incidentSampleId" ] }, + "ModelStatus": { + "type": "string", + "enum": [ + "created", + "training", + "ready", + "failed" + ], + "x-ms-enum": { + "name": "ModelStatus", + "modelAsString": true + } + }, "PagedImageIncident": { "type": "object", "description": "Paged collection of ImageIncident items", @@ -2630,20 +2900,26 @@ "value" ] }, - "PreDefinedConcept": { + "PagedTextTrainedModel": { "type": "object", - "description": "Pre-defined concept.", + "description": "Paged collection of TextTrainedModel items", "properties": { - "concept": { - "type": "string" + "value": { + "type": "array", + "description": "The TextTrainedModel items on this page", + "items": { + "$ref": "#/definitions/TextTrainedModel" + }, + "x-ms-identifiers": [] }, - "description": { - "type": "string" + "nextLink": { + "type": "string", + "format": "uri", + "description": "The link to the next page of items" } }, "required": [ - "concept", - "description" + "value" ] }, "ProtectedMaterialAnalysisResult": { @@ -2707,30 +2983,6 @@ "incidentSampleIds" ] }, - "SubCategory": { - "type": "object", - "description": "Label definition.", - "properties": { - "id": { - "type": "integer", - "format": "int32" - }, - "name": { - "type": "string" - }, - "statements": { - "type": "array", - "items": { - "type": "string" - } - } - }, - "required": [ - "id", - "name", - "statements" - ] - }, "Task": { "type": "string", "description": "Task type.", @@ -2886,33 +3138,60 @@ "create" ] }, - "preDefinedConcepts": { - "type": "array", - "items": { - "$ref": "#/definitions/PreDefinedConcept" - }, - "x-ms-identifiers": [] - }, - "subCategories": { + "classes": { "type": "array", + "description": "Subcategories are detailed classes of the category. It is required there is a class 'safe' with id=0.", "items": { - "$ref": "#/definitions/SubCategory" + "$ref": "#/definitions/Class" } }, - "emphases": { + "exampleBlobUrl": { + "type": "string", + "format": "uri", + "description": "Blob that stores the examples." + } + }, + "required": [ + "categoryName", + "classes" + ] + }, + "TextCustomizedCategoryAnalysis": { + "type": "object", + "description": "Text customized category analysis result.", + "properties": { + "categoryName": { + "type": "string", + "description": "Customized category name" + }, + "customizedCategoriesAnalysis": { "type": "array", + "description": "customized category analysis", "items": { - "type": "string" + "$ref": "#/definitions/TextCustomizedCategoryClassResult" } - }, - "exampleBlobUrl": { - "type": "string", - "format": "uri" } }, "required": [ "categoryName", - "subCategories" + "customizedCategoriesAnalysis" + ] + }, + "TextCustomizedCategoryClassResult": { + "type": "object", + "description": "customized category analysis result", + "properties": { + "id": { + "type": "integer", + "format": "int32" + }, + "className": { + "type": "string" + } + }, + "required": [ + "id", + "className" ] }, "TextIncident": { @@ -2998,6 +3277,44 @@ "incidentSampleId" ] }, + "TextTrainedModel": { + "type": "object", + "properties": { + "modelId": { + "type": "string" + }, + "status": { + "$ref": "#/definitions/ModelStatus" + }, + "createdTime": { + "type": "string", + "format": "date-time" + }, + "lastUpdateTime": { + "type": "string", + "format": "date-time" + }, + "warnings": { + "type": "array", + "items": { + "$ref": "#/definitions/AsyncJobWarning" + }, + "x-ms-identifiers": [] + }, + "errors": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "required": [ + "modelId", + "status", + "createdTime", + "lastUpdateTime" + ] + }, "UngroundedDetails": { "type": "object", "description": "The detailed information about a text identified as ungrounded.",