diff --git a/sdk/contentsafety/ai-content-safety-rest/CHANGELOG.md b/sdk/contentsafety/ai-content-safety-rest/CHANGELOG.md index 1ce623dfeef0..1cfafaacb724 100644 --- a/sdk/contentsafety/ai-content-safety-rest/CHANGELOG.md +++ b/sdk/contentsafety/ai-content-safety-rest/CHANGELOG.md @@ -1,14 +1,9 @@ # Release History -## 1.0.1 (Unreleased) +## 1.0.1 (2024-12-16) ### Features Added - -### Breaking Changes - -### Bugs Fixed - -### Other Changes +-refresh @azure-rest/ai-content-safety sdk ## 1.0.0 (2023-12-13) diff --git a/sdk/contentsafety/ai-content-safety-rest/eslint.config.mjs b/sdk/contentsafety/ai-content-safety-rest/eslint.config.mjs new file mode 100644 index 000000000000..b57e15e8e044 --- /dev/null +++ b/sdk/contentsafety/ai-content-safety-rest/eslint.config.mjs @@ -0,0 +1,9 @@ +import azsdkEslint from "@azure/eslint-plugin-azure-sdk"; + +export default azsdkEslint.config([ + { + rules: { + "@azure/azure-sdk/ts-modules-only-named": "warn", + }, + }, +]); diff --git a/sdk/contentsafety/ai-content-safety-rest/review/ai-content-safety.api.md b/sdk/contentsafety/ai-content-safety-rest/review/ai-content-safety.api.md index 32ddc49df2d7..ca99a20a89f7 100644 --- a/sdk/contentsafety/ai-content-safety-rest/review/ai-content-safety.api.md +++ b/sdk/contentsafety/ai-content-safety-rest/review/ai-content-safety.api.md @@ -9,8 +9,6 @@ import type { ClientOptions } from '@azure-rest/core-client'; import type { ErrorResponse } from '@azure-rest/core-client'; import type { HttpResponse } from '@azure-rest/core-client'; import type { KeyCredential } from '@azure/core-auth'; -import type { Paged } from '@azure/core-paging'; -import type { PagedAsyncIterableIterator } from '@azure/core-paging'; import type { PathUncheckedResponse } from '@azure-rest/core-client'; import type { RawHttpHeaders } from '@azure/core-rest-pipeline'; import type { RequestParameters } from '@azure-rest/core-client'; @@ -98,17 +96,13 @@ export interface AnalyzeImageDefaultResponse extends HttpResponse { // @public export interface AnalyzeImageOptions { - categories?: string[]; + categories?: ImageCategory[]; image: ImageData_2; - outputType?: string; + outputType?: AnalyzeImageOutputType; } // @public -export interface AnalyzeImageOptionsOutput { - categories?: string[]; - image: ImageDataOutput; - outputType?: string; -} +export type AnalyzeImageOutputType = string; // @public (undocumented) export type AnalyzeImageParameters = AnalyzeImageBodyParam & RequestParameters; @@ -154,20 +148,14 @@ export interface AnalyzeTextDefaultResponse extends HttpResponse { // @public export interface AnalyzeTextOptions { blocklistNames?: string[]; - categories?: string[]; + categories?: TextCategory[]; haltOnBlocklistHit?: boolean; - outputType?: string; + outputType?: AnalyzeTextOutputType; text: string; } // @public -export interface AnalyzeTextOptionsOutput { - blocklistNames?: string[]; - categories?: string[]; - haltOnBlocklistHit?: boolean; - outputType?: string; - text: string; -} +export type AnalyzeTextOutputType = string; // @public (undocumented) export type AnalyzeTextParameters = AnalyzeTextBodyParam & RequestParameters; @@ -184,7 +172,12 @@ export type ContentSafetyClient = Client & { }; // @public -function createClient(endpoint: string, credentials: TokenCredential | KeyCredential, options?: ClientOptions): ContentSafetyClient; +export interface ContentSafetyClientOptions extends ClientOptions { + apiVersion?: string; +} + +// @public +function createClient(endpointParam: string, credentials: TokenCredential | KeyCredential, { apiVersion, ...options }?: ContentSafetyClientOptions): ContentSafetyClient; export default createClient; // @public @@ -259,7 +252,7 @@ export type DeleteTextBlocklistParameters = RequestParameters; export type GetArrayType = T extends Array ? TData : never; // @public -export type GetPage = (pageLink: string, maxPageSize?: number) => Promise<{ +export type GetPage = (pageLink: string) => Promise<{ page: TPage; nextPageLink?: string; }>; @@ -330,28 +323,28 @@ export type GetTextBlocklistParameters = RequestParameters; // @public export interface ImageCategoriesAnalysisOutput { - category: string; + category: ImageCategoryOutput; severity?: number; } // @public -interface ImageData_2 { - blobUrl?: string; - content?: string; -} -export { ImageData_2 as ImageData } +export type ImageCategory = string; // @public -export interface ImageDataOutput { +export type ImageCategoryOutput = string; + +// @public +interface ImageData_2 { blobUrl?: string; content?: string; } +export { ImageData_2 as ImageData } // @public (undocumented) -export function isUnexpected(response: AnalyzeText200Response | AnalyzeTextDefaultResponse): response is AnalyzeTextDefaultResponse; +export function isUnexpected(response: AnalyzeImage200Response | AnalyzeImageDefaultResponse): response is AnalyzeImageDefaultResponse; // @public (undocumented) -export function isUnexpected(response: AnalyzeImage200Response | AnalyzeImageDefaultResponse): response is AnalyzeImageDefaultResponse; +export function isUnexpected(response: AnalyzeText200Response | AnalyzeTextDefaultResponse): response is AnalyzeTextDefaultResponse; // @public (undocumented) export function isUnexpected(response: GetTextBlocklist200Response | GetTextBlocklistDefaultResponse): response is GetTextBlocklistDefaultResponse; @@ -453,10 +446,28 @@ export interface ListTextBlocklistsDefaultResponse extends HttpResponse { export type ListTextBlocklistsParameters = RequestParameters; // @public -export type PagedTextBlocklistItemOutput = Paged; +export interface PagedAsyncIterableIterator { + [Symbol.asyncIterator](): PagedAsyncIterableIterator; + byPage: (settings?: TPageSettings) => AsyncIterableIterator; + next(): Promise>; +} // @public -export type PagedTextBlocklistOutput = Paged; +export interface PagedTextBlocklistItemOutput { + nextLink?: string; + value: Array; +} + +// @public +export interface PagedTextBlocklistOutput { + nextLink?: string; + value: Array; +} + +// @public +export interface PageSettings { + continuationToken?: string; +} // @public export function paginate(client: Client, initialResponse: TResponse, options?: PagingOptions): PagedAsyncIterableIterator>; @@ -514,8 +525,8 @@ export interface RemoveTextBlocklistItemsOptions { // @public (undocumented) export interface Routes { - (path: "/text:analyze"): AnalyzeText; (path: "/image:analyze"): AnalyzeImage; + (path: "/text:analyze"): AnalyzeText; (path: "/text/blocklists/{blocklistName}", blocklistName: string): GetTextBlocklist; (path: "/text/blocklists"): ListTextBlocklists; (path: "/text/blocklists/{blocklistName}:addOrUpdateBlocklistItems", blocklistName: string): AddOrUpdateBlocklistItems; @@ -561,10 +572,16 @@ export type TextBlocklistResourceMergeAndPatch = Partial; // @public export interface TextCategoriesAnalysisOutput { - category: string; + category: TextCategoryOutput; severity?: number; } +// @public +export type TextCategory = string; + +// @public +export type TextCategoryOutput = string; + // (No @packageDocumentation comment for this package) ``` diff --git a/sdk/contentsafety/ai-content-safety-rest/src/clientDefinitions.ts b/sdk/contentsafety/ai-content-safety-rest/src/clientDefinitions.ts index ffbd905cfc8a..c07e17869159 100644 --- a/sdk/contentsafety/ai-content-safety-rest/src/clientDefinitions.ts +++ b/sdk/contentsafety/ai-content-safety-rest/src/clientDefinitions.ts @@ -2,8 +2,8 @@ // Licensed under the MIT License. import type { - AnalyzeTextParameters, AnalyzeImageParameters, + AnalyzeTextParameters, GetTextBlocklistParameters, CreateOrUpdateTextBlocklistParameters, DeleteTextBlocklistParameters, @@ -14,10 +14,10 @@ import type { ListTextBlocklistItemsParameters, } from "./parameters.js"; import type { - AnalyzeText200Response, - AnalyzeTextDefaultResponse, AnalyzeImage200Response, AnalyzeImageDefaultResponse, + AnalyzeText200Response, + AnalyzeTextDefaultResponse, GetTextBlocklist200Response, GetTextBlocklistDefaultResponse, CreateOrUpdateTextBlocklist200Response, @@ -38,13 +38,6 @@ import type { } from "./responses.js"; import type { Client, StreamableMethod } from "@azure-rest/core-client"; -export interface AnalyzeText { - /** A synchronous API for the analysis of potentially harmful text content. Currently, it supports four categories: Hate, SelfHarm, Sexual, and Violence. */ - post( - options: AnalyzeTextParameters, - ): StreamableMethod; -} - export interface AnalyzeImage { /** A synchronous API for the analysis of potentially harmful image content. Currently, it supports four categories: Hate, SelfHarm, Sexual, and Violence. */ post( @@ -52,6 +45,13 @@ export interface AnalyzeImage { ): StreamableMethod; } +export interface AnalyzeText { + /** A synchronous API for the analysis of potentially harmful text content. Currently, it supports four categories: Hate, SelfHarm, Sexual, and Violence. */ + post( + options: AnalyzeTextParameters, + ): StreamableMethod; +} + export interface GetTextBlocklist { /** Returns text blocklist details. */ get( @@ -109,10 +109,10 @@ export interface ListTextBlocklistItems { } export interface Routes { - /** Resource for '/text:analyze' has methods for the following verbs: post */ - (path: "/text:analyze"): AnalyzeText; /** Resource for '/image:analyze' has methods for the following verbs: post */ (path: "/image:analyze"): AnalyzeImage; + /** Resource for '/text:analyze' has methods for the following verbs: post */ + (path: "/text:analyze"): AnalyzeText; /** Resource for '/text/blocklists/\{blocklistName\}' has methods for the following verbs: get, patch, delete */ (path: "/text/blocklists/{blocklistName}", blocklistName: string): GetTextBlocklist; /** Resource for '/text/blocklists' has methods for the following verbs: get */ diff --git a/sdk/contentsafety/ai-content-safety-rest/src/contentSafetyClient.ts b/sdk/contentsafety/ai-content-safety-rest/src/contentSafetyClient.ts index b283bcc5e8a8..a85c0491bcdb 100644 --- a/sdk/contentsafety/ai-content-safety-rest/src/contentSafetyClient.ts +++ b/sdk/contentsafety/ai-content-safety-rest/src/contentSafetyClient.ts @@ -7,20 +7,25 @@ import { logger } from "./logger.js"; import type { TokenCredential, KeyCredential } from "@azure/core-auth"; import type { ContentSafetyClient } from "./clientDefinitions.js"; +/** The optional parameters for the client */ +export interface ContentSafetyClientOptions extends ClientOptions { + /** The api version option of the client */ + apiVersion?: string; +} + /** * Initialize a new instance of `ContentSafetyClient` - * @param endpoint - Supported Cognitive Services endpoints (protocol and hostname, for example: + * @param endpointParam - Supported Cognitive Services endpoints (protocol and hostname, for example: * https://.cognitiveservices.azure.com). * @param credentials - uniquely identify client credential * @param options - the parameter for all optional parameters */ export default function createClient( - endpoint: string, + endpointParam: string, credentials: TokenCredential | KeyCredential, - options: ClientOptions = {}, + { apiVersion = "2023-10-01", ...options }: ContentSafetyClientOptions = {}, ): ContentSafetyClient { - const baseUrl = options.baseUrl ?? `${endpoint}/contentsafety`; - options.apiVersion = options.apiVersion ?? "2023-10-01"; + const endpointUrl = options.endpoint ?? options.baseUrl ?? `${endpointParam}/contentsafety`; const userAgentInfo = `azsdk-js-ai-content-safety-rest/1.0.1`; const userAgentPrefix = options.userAgentOptions && options.userAgentOptions.userAgentPrefix @@ -39,8 +44,24 @@ export default function createClient( apiKeyHeaderName: options.credentials?.apiKeyHeaderName ?? "Ocp-Apim-Subscription-Key", }, }; + const client = getClient(endpointUrl, credentials, options) as ContentSafetyClient; - const client = getClient(baseUrl, credentials, options) as ContentSafetyClient; + client.pipeline.removePolicy({ name: "ApiVersionPolicy" }); + client.pipeline.addPolicy({ + name: "ClientApiVersionPolicy", + sendRequest: (req, next) => { + // Use the apiVersion defined in request url directly + // Append one if there is no apiVersion and we have one at client options + const url = new URL(req.url); + if (!url.searchParams.get("api-version") && apiVersion) { + req.url = `${req.url}${ + Array.from(url.searchParams.keys()).length > 0 ? "&" : "?" + }api-version=${apiVersion}`; + } + + return next(req); + }, + }); return client; } diff --git a/sdk/contentsafety/ai-content-safety-rest/src/index.ts b/sdk/contentsafety/ai-content-safety-rest/src/index.ts index 445b49c6bfe9..b0791e7a658a 100644 --- a/sdk/contentsafety/ai-content-safety-rest/src/index.ts +++ b/sdk/contentsafety/ai-content-safety-rest/src/index.ts @@ -12,5 +12,4 @@ export * from "./models.js"; export * from "./outputModels.js"; export * from "./paginateHelper.js"; -// eslint-disable-next-line @azure/azure-sdk/ts-modules-only-named export default ContentSafetyClient; diff --git a/sdk/contentsafety/ai-content-safety-rest/src/isUnexpected.ts b/sdk/contentsafety/ai-content-safety-rest/src/isUnexpected.ts index 382b7d3dd252..d6828ae15ce2 100644 --- a/sdk/contentsafety/ai-content-safety-rest/src/isUnexpected.ts +++ b/sdk/contentsafety/ai-content-safety-rest/src/isUnexpected.ts @@ -2,10 +2,10 @@ // Licensed under the MIT License. import type { - AnalyzeText200Response, - AnalyzeTextDefaultResponse, AnalyzeImage200Response, AnalyzeImageDefaultResponse, + AnalyzeText200Response, + AnalyzeTextDefaultResponse, GetTextBlocklist200Response, GetTextBlocklistDefaultResponse, CreateOrUpdateTextBlocklist200Response, @@ -26,8 +26,8 @@ import type { } from "./responses.js"; const responseMap: Record = { - "POST /text:analyze": ["200"], "POST /image:analyze": ["200"], + "POST /text:analyze": ["200"], "GET /text/blocklists/{blocklistName}": ["200"], "PATCH /text/blocklists/{blocklistName}": ["200", "201"], "DELETE /text/blocklists/{blocklistName}": ["204"], @@ -38,12 +38,12 @@ const responseMap: Record = { "GET /text/blocklists/{blocklistName}/blocklistItems": ["200"], }; -export function isUnexpected( - response: AnalyzeText200Response | AnalyzeTextDefaultResponse, -): response is AnalyzeTextDefaultResponse; export function isUnexpected( response: AnalyzeImage200Response | AnalyzeImageDefaultResponse, ): response is AnalyzeImageDefaultResponse; +export function isUnexpected( + response: AnalyzeText200Response | AnalyzeTextDefaultResponse, +): response is AnalyzeTextDefaultResponse; export function isUnexpected( response: GetTextBlocklist200Response | GetTextBlocklistDefaultResponse, ): response is GetTextBlocklistDefaultResponse; @@ -73,10 +73,10 @@ export function isUnexpected( ): response is ListTextBlocklistItemsDefaultResponse; export function isUnexpected( response: - | AnalyzeText200Response - | AnalyzeTextDefaultResponse | AnalyzeImage200Response | AnalyzeImageDefaultResponse + | AnalyzeText200Response + | AnalyzeTextDefaultResponse | GetTextBlocklist200Response | GetTextBlocklistDefaultResponse | CreateOrUpdateTextBlocklist200Response @@ -95,8 +95,8 @@ export function isUnexpected( | ListTextBlocklistItems200Response | ListTextBlocklistItemsDefaultResponse, ): response is - | AnalyzeTextDefaultResponse | AnalyzeImageDefaultResponse + | AnalyzeTextDefaultResponse | GetTextBlocklistDefaultResponse | CreateOrUpdateTextBlocklistDefaultResponse | DeleteTextBlocklistDefaultResponse diff --git a/sdk/contentsafety/ai-content-safety-rest/src/models.ts b/sdk/contentsafety/ai-content-safety-rest/src/models.ts index d416722083f8..017c38a6216a 100644 --- a/sdk/contentsafety/ai-content-safety-rest/src/models.ts +++ b/sdk/contentsafety/ai-content-safety-rest/src/models.ts @@ -1,36 +1,18 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -/** The text analysis request. */ -export interface AnalyzeTextOptions { - /** The text needs to be analyzed. We support a maximum of 10k Unicode characters (Unicode code points) in the text of one request. */ - text: string; - /** The categories will be analyzed. If they are not assigned, a default set of analysis results for the categories will be returned. */ - categories?: string[]; - /** The names of blocklists. */ - blocklistNames?: string[]; - /** When set to true, further analyses of harmful content will not be performed in cases where blocklists are hit. When set to false, all analyses of harmful content will be performed, whether or not blocklists are hit. */ - haltOnBlocklistHit?: boolean; - /** - * This refers to the type of text analysis output. If no value is assigned, the default value will be "FourSeverityLevels". - * - * Possible values: FourSeverityLevels, EightSeverityLevels - */ - outputType?: string; -} - /** The image analysis request. */ export interface AnalyzeImageOptions { - /** The image needs to be analyzed. */ + /** The image to be analyzed. */ image: ImageData; /** The categories will be analyzed. If they are not assigned, a default set of analysis results for the categories will be returned. */ - categories?: string[]; + categories?: ImageCategory[]; /** * This refers to the type of image analysis output. If no value is assigned, the default value will be "FourSeverityLevels". * - * Possible values: FourSeverityLevels + * Possible values: "FourSeverityLevels" */ - outputType?: string; + outputType?: AnalyzeImageOutputType; } /** The image can be either base64 encoded bytes or a blob URL. You can choose only one of these options. If both are provided, the request will be refused. The maximum image size is 2048 x 2048 pixels and should not exceed 4 MB, while the minimum image size is 50 x 50 pixels. */ @@ -41,6 +23,24 @@ export interface ImageData { blobUrl?: string; } +/** The text analysis request. */ +export interface AnalyzeTextOptions { + /** The text to be analyzed. We support a maximum of 10k Unicode characters (Unicode code points) in the text of one request. */ + text: string; + /** The categories will be analyzed. If they are not assigned, a default set of analysis results for the categories will be returned. */ + categories?: TextCategory[]; + /** The names of blocklists. */ + blocklistNames?: string[]; + /** When set to true, further analyses of harmful content will not be performed in cases where blocklists are hit. When set to false, all analyses of harmful content will be performed, whether or not blocklists are hit. */ + haltOnBlocklistHit?: boolean; + /** + * This refers to the type of text analysis output. If no value is assigned, the default value will be "FourSeverityLevels". + * + * Possible values: "FourSeverityLevels", "EightSeverityLevels" + */ + outputType?: AnalyzeTextOutputType; +} + /** Text Blocklist. */ export interface TextBlocklist { /** Text blocklist name. */ @@ -59,7 +59,7 @@ export interface AddOrUpdateTextBlocklistItemsOptions { export interface TextBlocklistItem { /** BlocklistItem description. */ description?: string; - /** BlocklistItem content. */ + /** BlocklistItem content. The length is counted using Unicode code point. */ text: string; } @@ -68,3 +68,12 @@ export interface RemoveTextBlocklistItemsOptions { /** Array of blocklistItemIds to remove. */ blocklistItemIds: string[]; } + +/** Alias for ImageCategory */ +export type ImageCategory = string; +/** Alias for AnalyzeImageOutputType */ +export type AnalyzeImageOutputType = string; +/** Alias for TextCategory */ +export type TextCategory = string; +/** Alias for AnalyzeTextOutputType */ +export type AnalyzeTextOutputType = string; diff --git a/sdk/contentsafety/ai-content-safety-rest/src/outputModels.ts b/sdk/contentsafety/ai-content-safety-rest/src/outputModels.ts index 5436bd44eff4..190ff141f733 100644 --- a/sdk/contentsafety/ai-content-safety-rest/src/outputModels.ts +++ b/sdk/contentsafety/ai-content-safety-rest/src/outputModels.ts @@ -1,24 +1,22 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { Paged } from "@azure/core-paging"; +/** The image analysis response. */ +export interface AnalyzeImageResultOutput { + /** Analysis result for categories. */ + categoriesAnalysis: Array; +} -/** The text analysis request. */ -export interface AnalyzeTextOptionsOutput { - /** The text needs to be analyzed. We support a maximum of 10k Unicode characters (Unicode code points) in the text of one request. */ - text: string; - /** The categories will be analyzed. If they are not assigned, a default set of analysis results for the categories will be returned. */ - categories?: string[]; - /** The names of blocklists. */ - blocklistNames?: string[]; - /** When set to true, further analyses of harmful content will not be performed in cases where blocklists are hit. When set to false, all analyses of harmful content will be performed, whether or not blocklists are hit. */ - haltOnBlocklistHit?: boolean; +/** Image analysis result. */ +export interface ImageCategoriesAnalysisOutput { /** - * This refers to the type of text analysis output. If no value is assigned, the default value will be "FourSeverityLevels". + * The image analysis category. * - * Possible values: FourSeverityLevels, EightSeverityLevels + * Possible values: "Hate", "SelfHarm", "Sexual", "Violence" */ - outputType?: string; + category: ImageCategoryOutput; + /** The value increases with the severity of the input content. The value of this field is determined by the output type specified in the request. The output type could be ‘FourSeverityLevels’, and the output value can be 0, 2, 4, 6. */ + severity?: number; } /** The text analysis response. */ @@ -44,53 +42,13 @@ export interface TextCategoriesAnalysisOutput { /** * The text analysis category. * - * Possible values: Hate, SelfHarm, Sexual, Violence + * Possible values: "Hate", "SelfHarm", "Sexual", "Violence" */ - category: string; + category: TextCategoryOutput; /** The value increases with the severity of the input content. The value of this field is determined by the output type specified in the request. The output type could be ‘FourSeverityLevels’ or ‘EightSeverity Levels’, and the output value can be 0, 2, 4, 6 or 0, 1, 2, 3, 4, 5, 6, or 7. */ severity?: number; } -/** The image analysis request. */ -export interface AnalyzeImageOptionsOutput { - /** The image needs to be analyzed. */ - image: ImageDataOutput; - /** The categories will be analyzed. If they are not assigned, a default set of analysis results for the categories will be returned. */ - categories?: string[]; - /** - * This refers to the type of image analysis output. If no value is assigned, the default value will be "FourSeverityLevels". - * - * Possible values: FourSeverityLevels - */ - outputType?: string; -} - -/** The image can be either base64 encoded bytes or a blob URL. You can choose only one of these options. If both are provided, the request will be refused. The maximum image size is 2048 x 2048 pixels and should not exceed 4 MB, while the minimum image size is 50 x 50 pixels. */ -export interface ImageDataOutput { - /** The Base64 encoding of the image. */ - content?: string; - /** The blob url of the image. */ - blobUrl?: string; -} - -/** The image analysis response. */ -export interface AnalyzeImageResultOutput { - /** Analysis result for categories. */ - categoriesAnalysis: Array; -} - -/** Image analysis result. */ -export interface ImageCategoriesAnalysisOutput { - /** - * The image analysis category. - * - * Possible values: Hate, SelfHarm, Sexual, Violence - */ - category: string; - /** The value increases with the severity of the input content. The value of this field is determined by the output type specified in the request. The output type could be ‘FourSeverityLevels’, and the output value can be 0, 2, 4, 6. */ - severity?: number; -} - /** Text Blocklist. */ export interface TextBlocklistOutput { /** Text blocklist name. */ @@ -99,13 +57,21 @@ export interface TextBlocklistOutput { description?: string; } +/** Paged collection of TextBlocklist items */ +export interface PagedTextBlocklistOutput { + /** The TextBlocklist items on this page */ + value: Array; + /** The link to the next page of items */ + nextLink?: string; +} + /** Item in a TextBlocklist. */ export interface TextBlocklistItemOutput { /** The service will generate a BlocklistItemId, which will be a UUID. */ readonly blocklistItemId: string; /** BlocklistItem description. */ description?: string; - /** BlocklistItem content. */ + /** BlocklistItem content. The length is counted using Unicode code point. */ text: string; } @@ -115,7 +81,15 @@ export interface AddOrUpdateTextBlocklistItemsResultOutput { blocklistItems: Array; } -/** Paged collection of TextBlocklist items */ -export type PagedTextBlocklistOutput = Paged; /** Paged collection of TextBlocklistItem items */ -export type PagedTextBlocklistItemOutput = Paged; +export interface PagedTextBlocklistItemOutput { + /** The TextBlocklistItem items on this page */ + value: Array; + /** The link to the next page of items */ + nextLink?: string; +} + +/** Alias for ImageCategoryOutput */ +export type ImageCategoryOutput = string; +/** Alias for TextCategoryOutput */ +export type TextCategoryOutput = string; diff --git a/sdk/contentsafety/ai-content-safety-rest/src/paginateHelper.ts b/sdk/contentsafety/ai-content-safety-rest/src/paginateHelper.ts index 5d541b4e406d..9ea946d9d6c5 100644 --- a/sdk/contentsafety/ai-content-safety-rest/src/paginateHelper.ts +++ b/sdk/contentsafety/ai-content-safety-rest/src/paginateHelper.ts @@ -1,11 +1,148 @@ // Copyright (c) Microsoft Corporation. // Licensed under the MIT License. -import type { PagedAsyncIterableIterator, PagedResult } from "@azure/core-paging"; -import { getPagedAsyncIterator } from "@azure/core-paging"; import type { Client, PathUncheckedResponse } from "@azure-rest/core-client"; import { createRestError } from "@azure-rest/core-client"; +/** + * returns an async iterator that iterates over results. It also has a `byPage` + * method that returns pages of items at once. + * + * @param pagedResult - an object that specifies how to get pages. + * @returns a paged async iterator that iterates over results. + */ +function getPagedAsyncIterator< + TElement, + TPage = TElement[], + TPageSettings = PageSettings, + TLink = string, +>( + pagedResult: PagedResult, +): PagedAsyncIterableIterator { + const iter = getItemAsyncIterator(pagedResult); + return { + next() { + return iter.next(); + }, + [Symbol.asyncIterator]() { + return this; + }, + byPage: + pagedResult?.byPage ?? + (((settings?: PageSettings) => { + const { continuationToken } = settings ?? {}; + return getPageAsyncIterator(pagedResult, { + pageLink: continuationToken as unknown as TLink | undefined, + }); + }) as unknown as (settings?: TPageSettings) => AsyncIterableIterator), + }; +} + +async function* getItemAsyncIterator( + pagedResult: PagedResult, +): AsyncIterableIterator { + const pages = getPageAsyncIterator(pagedResult); + const firstVal = await pages.next(); + // if the result does not have an array shape, i.e. TPage = TElement, then we return it as is + if (!Array.isArray(firstVal.value)) { + // can extract elements from this page + const { toElements } = pagedResult; + if (toElements) { + yield* toElements(firstVal.value) as TElement[]; + for await (const page of pages) { + yield* toElements(page) as TElement[]; + } + } else { + yield firstVal.value; + // `pages` is of type `AsyncIterableIterator` but TPage = TElement in this case + yield* pages as unknown as AsyncIterableIterator; + } + } else { + yield* firstVal.value; + for await (const page of pages) { + // pages is of type `AsyncIterableIterator` so `page` is of type `TPage`. In this branch, + // it must be the case that `TPage = TElement[]` + yield* page as unknown as TElement[]; + } + } +} + +async function* getPageAsyncIterator( + pagedResult: PagedResult, + options: { + pageLink?: TLink; + } = {}, +): AsyncIterableIterator { + const { pageLink } = options; + let response = await pagedResult.getPage(pageLink ?? pagedResult.firstPageLink); + if (!response) { + return; + } + yield response.page; + while (response.nextPageLink) { + response = await pagedResult.getPage(response.nextPageLink); + if (!response) { + return; + } + yield response.page; + } +} + +/** + * An interface that tracks the settings for paged iteration + */ +export interface PageSettings { + /** + * The token that keeps track of where to continue the iterator + */ + continuationToken?: string; +} + +/** + * An interface that allows async iterable iteration both to completion and by page. + */ +export interface PagedAsyncIterableIterator< + TElement, + TPage = TElement[], + TPageSettings = PageSettings, +> { + /** + * The next method, part of the iteration protocol + */ + next(): Promise>; + /** + * The connection to the async iterator, part of the iteration protocol + */ + [Symbol.asyncIterator](): PagedAsyncIterableIterator; + /** + * Return an AsyncIterableIterator that works a page at a time + */ + byPage: (settings?: TPageSettings) => AsyncIterableIterator; +} + +/** + * An interface that describes how to communicate with the service. + */ +interface PagedResult { + /** + * Link to the first page of results. + */ + firstPageLink: TLink; + /** + * A method that returns a page of results. + */ + getPage: (pageLink: TLink) => Promise<{ page: TPage; nextPageLink?: TLink } | undefined>; + /** + * a function to implement the `byPage` method on the paged async iterator. + */ + byPage?: (settings?: TPageSettings) => AsyncIterableIterator; + + /** + * A function to extract elements from a page. + */ + toElements?: (page: TPage) => unknown[]; +} + /** * Helper type to extract the type of an array */ @@ -14,10 +151,7 @@ export type GetArrayType = T extends Array ? TData : never; /** * The type of a custom function that defines how to get a page and a link to the next one if any. */ -export type GetPage = ( - pageLink: string, - maxPageSize?: number, -) => Promise<{ +export type GetPage = (pageLink: string) => Promise<{ page: TPage; nextPageLink?: string; }>; diff --git a/sdk/contentsafety/ai-content-safety-rest/src/parameters.ts b/sdk/contentsafety/ai-content-safety-rest/src/parameters.ts index b787eb2d0e7b..aec66e9a4ed9 100644 --- a/sdk/contentsafety/ai-content-safety-rest/src/parameters.ts +++ b/sdk/contentsafety/ai-content-safety-rest/src/parameters.ts @@ -3,26 +3,26 @@ import type { RequestParameters } from "@azure-rest/core-client"; import type { - AnalyzeTextOptions, AnalyzeImageOptions, + AnalyzeTextOptions, TextBlocklist, AddOrUpdateTextBlocklistItemsOptions, RemoveTextBlocklistItemsOptions, } from "./models.js"; -export interface AnalyzeTextBodyParam { - /** The text analysis request. */ - body: AnalyzeTextOptions; -} - -export type AnalyzeTextParameters = AnalyzeTextBodyParam & RequestParameters; - export interface AnalyzeImageBodyParam { /** The image analysis request. */ body: AnalyzeImageOptions; } export type AnalyzeImageParameters = AnalyzeImageBodyParam & RequestParameters; + +export interface AnalyzeTextBodyParam { + /** The text analysis request. */ + body: AnalyzeTextOptions; +} + +export type AnalyzeTextParameters = AnalyzeTextBodyParam & RequestParameters; export type GetTextBlocklistParameters = RequestParameters; /** The resource instance. */ export type TextBlocklistResourceMergeAndPatch = Partial; diff --git a/sdk/contentsafety/ai-content-safety-rest/src/responses.ts b/sdk/contentsafety/ai-content-safety-rest/src/responses.ts index b5bef7d4fce1..a82e9ceb8d00 100644 --- a/sdk/contentsafety/ai-content-safety-rest/src/responses.ts +++ b/sdk/contentsafety/ai-content-safety-rest/src/responses.ts @@ -4,8 +4,8 @@ import type { RawHttpHeaders } from "@azure/core-rest-pipeline"; import type { HttpResponse, ErrorResponse } from "@azure-rest/core-client"; import type { - AnalyzeTextResultOutput, AnalyzeImageResultOutput, + AnalyzeTextResultOutput, TextBlocklistOutput, PagedTextBlocklistOutput, AddOrUpdateTextBlocklistItemsResultOutput, @@ -14,37 +14,37 @@ import type { } from "./outputModels.js"; /** The request has succeeded. */ -export interface AnalyzeText200Response extends HttpResponse { +export interface AnalyzeImage200Response extends HttpResponse { status: "200"; - body: AnalyzeTextResultOutput; + body: AnalyzeImageResultOutput; } -export interface AnalyzeTextDefaultHeaders { +export interface AnalyzeImageDefaultHeaders { /** String error code indicating what went wrong. */ "x-ms-error-code"?: string; } -export interface AnalyzeTextDefaultResponse extends HttpResponse { +export interface AnalyzeImageDefaultResponse extends HttpResponse { status: string; body: ErrorResponse; - headers: RawHttpHeaders & AnalyzeTextDefaultHeaders; + headers: RawHttpHeaders & AnalyzeImageDefaultHeaders; } /** The request has succeeded. */ -export interface AnalyzeImage200Response extends HttpResponse { +export interface AnalyzeText200Response extends HttpResponse { status: "200"; - body: AnalyzeImageResultOutput; + body: AnalyzeTextResultOutput; } -export interface AnalyzeImageDefaultHeaders { +export interface AnalyzeTextDefaultHeaders { /** String error code indicating what went wrong. */ "x-ms-error-code"?: string; } -export interface AnalyzeImageDefaultResponse extends HttpResponse { +export interface AnalyzeTextDefaultResponse extends HttpResponse { status: string; body: ErrorResponse; - headers: RawHttpHeaders & AnalyzeImageDefaultHeaders; + headers: RawHttpHeaders & AnalyzeTextDefaultHeaders; } /** The request has succeeded. */ diff --git a/sdk/contentsafety/ai-content-safety-rest/tsp-location.yaml b/sdk/contentsafety/ai-content-safety-rest/tsp-location.yaml index 9d47983f6b57..a607d2e6fafe 100644 --- a/sdk/contentsafety/ai-content-safety-rest/tsp-location.yaml +++ b/sdk/contentsafety/ai-content-safety-rest/tsp-location.yaml @@ -1,3 +1,4 @@ directory: specification/cognitiveservices/ContentSafety -repo: Azure/azure-rest-api-specs -commit: 164375e67a1bffb207bcf603772c289dbe42d7b5 +commit: d85dc63616d14d9790b224d46aad024e3461955b +repo: ../azure-rest-api-specs +additionalDirectories: