@azure/ai-text-analytics
Version:
An isomorphic client library for the Azure Text Analytics service.
504 lines • 20.8 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
import { __rest } from "tslib";
import { bearerTokenAuthenticationPolicy } from "@azure/core-rest-pipeline";
import { isTokenCredential } from "@azure/core-auth";
import { SDK_VERSION } from "./constants";
import { GeneratedClient } from "./generated/generatedClient";
import { logger } from "./logger";
import { makeDetectLanguageResultArray } from "./detectLanguageResultArray";
import { makeRecognizeCategorizedEntitiesResultArray } from "./recognizeCategorizedEntitiesResultArray";
import { makeAnalyzeSentimentResultArray } from "./analyzeSentimentResultArray";
import { makeExtractKeyPhrasesResultArray } from "./extractKeyPhrasesResultArray";
import { makeRecognizePiiEntitiesResultArray } from "./recognizePiiEntitiesResultArray";
import { makeRecognizeLinkedEntitiesResultArray } from "./recognizeLinkedEntitiesResultArray";
import { createSpan } from "./tracing";
import { SpanStatusCode } from "@azure/core-tracing";
import { textAnalyticsAzureKeyCredentialPolicy } from "./azureKeyCredentialPolicy";
import { addParamsToTask, compose, handleInvalidDocumentBatch, setCategoriesFilter, setOpinionMining, setStrEncodingParam, setStrEncodingParamValue } from "./util";
import { BeginAnalyzeHealthcarePoller } from "./lro/health/poller";
import { BeginAnalyzeActionsPoller } from "./lro/analyze/poller";
const DEFAULT_COGNITIVE_SCOPE = "https://cognitiveservices.azure.com/.default";
/**
* The types of PII domains the user can choose from.
*/
export var PiiEntityDomain;
(function (PiiEntityDomain) {
/**
* @see {@link https://aka.ms/tanerpii} for more information.
*/
PiiEntityDomain["PROTECTED_HEALTH_INFORMATION"] = "PHI";
})(PiiEntityDomain || (PiiEntityDomain = {}));
/**
* Client class for interacting with Azure Text Analytics.
*/
export class TextAnalyticsClient {
/**
* Creates an instance of TextAnalyticsClient.
*
* Example usage:
* ```ts
* import { TextAnalyticsClient, AzureKeyCredential } from "@azure/ai-text-analytics";
*
* const client = new TextAnalyticsClient(
* "<service endpoint>",
* new AzureKeyCredential("<api key>")
* );
* ```
* @param endpointUrl - The URL to the TextAnalytics endpoint
* @param credential - Used to authenticate requests to the service.
* @param options - Used to configure the TextAnalytics client.
*/
constructor(endpointUrl, credential, options = {}) {
this.endpointUrl = endpointUrl;
const { defaultCountryHint = "us", defaultLanguage = "en" } = options, pipelineOptions = __rest(options, ["defaultCountryHint", "defaultLanguage"]);
this.defaultCountryHint = defaultCountryHint;
this.defaultLanguage = defaultLanguage;
const libInfo = `azsdk-js-ai-textanalytics/${SDK_VERSION}`;
if (!pipelineOptions.userAgentOptions) {
pipelineOptions.userAgentOptions = {};
}
if (pipelineOptions.userAgentOptions.userAgentPrefix) {
pipelineOptions.userAgentOptions.userAgentPrefix = `${pipelineOptions.userAgentOptions.userAgentPrefix} ${libInfo}`;
}
else {
pipelineOptions.userAgentOptions.userAgentPrefix = libInfo;
}
const internalPipelineOptions = Object.assign(Object.assign({}, pipelineOptions), {
loggingOptions: {
logger: logger.info,
additionalAllowedHeaderNames: ["x-ms-correlation-request-id", "x-ms-request-id"]
}
});
this.client = new GeneratedClient(this.endpointUrl, internalPipelineOptions);
const authPolicy = isTokenCredential(credential)
? bearerTokenAuthenticationPolicy({ credential, scopes: DEFAULT_COGNITIVE_SCOPE })
: textAnalyticsAzureKeyCredentialPolicy(credential);
this.client.pipeline.addPolicy(authPolicy);
}
async detectLanguage(documents, countryHintOrOptions, options) {
let realOptions;
let realInputs;
if (!Array.isArray(documents) || documents.length === 0) {
throw new Error("'documents' must be a non-empty array");
}
if (isStringArray(documents)) {
const countryHint = countryHintOrOptions || this.defaultCountryHint;
realInputs = convertToDetectLanguageInput(documents, countryHint);
realOptions = options || {};
}
else {
// Replace "none" hints with ""
realInputs = documents.map((input) => (Object.assign(Object.assign({}, input), { countryHint: input.countryHint === "none" ? "" : input.countryHint })));
realOptions = countryHintOrOptions || {};
}
const { span, updatedOptions: finalOptions } = createSpan("TextAnalyticsClient-detectLanguages", makeGeneratedDetectLanguageOptions(realOptions));
try {
const result = await this.client.languages({
documents: realInputs
}, finalOptions);
return makeDetectLanguageResultArray(realInputs, result);
}
catch (e) {
span.setStatus({
code: SpanStatusCode.ERROR,
message: e.message
});
throw e;
}
finally {
span.end();
}
}
async recognizeEntities(documents, languageOrOptions,
// eslint-disable-next-line @azure/azure-sdk/ts-naming-options
options) {
let realOptions;
let realInputs;
if (!Array.isArray(documents) || documents.length === 0) {
throw new Error("'documents' must be a non-empty array");
}
if (isStringArray(documents)) {
const language = languageOrOptions || this.defaultLanguage;
realInputs = convertToTextDocumentInput(documents, language);
realOptions = options || {};
}
else {
realInputs = documents;
realOptions = languageOrOptions || {};
}
const { span, updatedOptions: finalOptions } = createSpan("TextAnalyticsClient-recognizeEntities", makeGeneratedRecognizeCategorizedEntitiesOptions(realOptions));
try {
const result = await this.client.entitiesRecognitionGeneral({
documents: realInputs
}, finalOptions);
return makeRecognizeCategorizedEntitiesResultArray(realInputs, result);
}
catch (e) {
/**
* This special logic handles REST exception with code
* InvalidDocumentBatch and is needed to maintain backward compatability
* with sdk v5.0.0 and earlier. In general, REST exceptions are thrown as
* is and include both outer and inner exception codes. However, the
* earlier versions were throwing an exception that included the inner
* code only.
*/
const backwardCompatibleException = handleInvalidDocumentBatch(e);
span.setStatus({
code: SpanStatusCode.ERROR,
message: backwardCompatibleException.message
});
throw backwardCompatibleException;
}
finally {
span.end();
}
}
async analyzeSentiment(documents, languageOrOptions, options) {
let realOptions;
let realInputs;
if (!Array.isArray(documents) || documents.length === 0) {
throw new Error("'documents' must be a non-empty array");
}
if (isStringArray(documents)) {
const language = languageOrOptions || this.defaultLanguage;
realInputs = convertToTextDocumentInput(documents, language);
realOptions = options || {};
}
else {
realInputs = documents;
realOptions = languageOrOptions || {};
}
const { span, updatedOptions: finalOptions } = createSpan("TextAnalyticsClient-analyzeSentiment", makeGeneratedAnalyzeSentimentOptions(realOptions));
try {
const result = await this.client.sentiment({
documents: realInputs
}, finalOptions);
return makeAnalyzeSentimentResultArray(realInputs, result);
}
catch (e) {
span.setStatus({
code: SpanStatusCode.ERROR,
message: e.message
});
throw e;
}
finally {
span.end();
}
}
async extractKeyPhrases(documents, languageOrOptions, options) {
let realOptions;
let realInputs;
if (!Array.isArray(documents) || documents.length === 0) {
throw new Error("'documents' must be a non-empty array");
}
if (isStringArray(documents)) {
const language = languageOrOptions || this.defaultLanguage;
realInputs = convertToTextDocumentInput(documents, language);
realOptions = options || {};
}
else {
realInputs = documents;
realOptions = languageOrOptions || {};
}
const { span, updatedOptions: finalOptions } = createSpan("TextAnalyticsClient-extractKeyPhrases", makeGeneratedExtractKeyPhrasesOptions(realOptions));
try {
const result = await this.client.keyPhrases({
documents: realInputs
}, finalOptions);
return makeExtractKeyPhrasesResultArray(realInputs, result);
}
catch (e) {
span.setStatus({
code: SpanStatusCode.ERROR,
message: e.message
});
throw e;
}
finally {
span.end();
}
}
async recognizePiiEntities(inputs, languageOrOptions, options) {
let realOptions;
let realInputs;
if (isStringArray(inputs)) {
const language = languageOrOptions || this.defaultLanguage;
realInputs = convertToTextDocumentInput(inputs, language);
realOptions = options || {};
}
else {
realInputs = inputs;
realOptions = languageOrOptions || {};
}
const { span, updatedOptions: finalOptions } = createSpan("TextAnalyticsClient-recognizePiiEntities", makeGeneratedRecognizePiiEntitiesOptions(realOptions));
try {
const result = await this.client.entitiesRecognitionPii({
documents: realInputs
}, finalOptions);
return makeRecognizePiiEntitiesResultArray(realInputs, result);
}
catch (e) {
span.setStatus({
code: SpanStatusCode.ERROR,
message: e.message
});
throw e;
}
finally {
span.end();
}
}
async recognizeLinkedEntities(documents, languageOrOptions, options) {
let realOptions;
let realInputs;
if (!Array.isArray(documents) || documents.length === 0) {
throw new Error("'documents' must be a non-empty array");
}
if (isStringArray(documents)) {
const language = languageOrOptions || this.defaultLanguage;
realInputs = convertToTextDocumentInput(documents, language);
realOptions = options || {};
}
else {
realInputs = documents;
realOptions = languageOrOptions || {};
}
const { span, updatedOptions: finalOptions } = createSpan("TextAnalyticsClient-recognizeLinkedEntities", makeGeneratedRecognizeLinkingEntitiesOptions(realOptions));
try {
const result = await this.client.entitiesLinking({
documents: realInputs
}, finalOptions);
return makeRecognizeLinkedEntitiesResultArray(realInputs, result);
}
catch (e) {
span.setStatus({
code: SpanStatusCode.ERROR,
message: e.message
});
throw e;
}
finally {
span.end();
}
}
async beginAnalyzeHealthcareEntities(documents, languageOrOptions, options) {
let realOptions;
let realInputs;
if (isStringArray(documents)) {
const language = languageOrOptions || this.defaultLanguage;
realInputs = convertToTextDocumentInput(documents, language);
realOptions = options || {};
}
else {
realInputs = documents;
realOptions = languageOrOptions || {};
}
const { updateIntervalInMs, resumeFrom } = realOptions, restOptions = __rest(realOptions, ["updateIntervalInMs", "resumeFrom"]);
const poller = new BeginAnalyzeHealthcarePoller({
client: this.client,
documents: realInputs,
options: restOptions,
updateIntervalInMs: updateIntervalInMs,
resumeFrom: resumeFrom
});
await poller.poll();
return poller;
}
async beginAnalyzeActions(documents, actions, languageOrOptions, options) {
let realOptions;
let realInputs;
if (!Array.isArray(documents) || documents.length === 0) {
throw new Error("'documents' must be a non-empty array");
}
if (isStringArray(documents)) {
const language = languageOrOptions || this.defaultLanguage;
realInputs = convertToTextDocumentInput(documents, language);
realOptions = options || {};
}
else {
realInputs = documents;
realOptions = languageOrOptions || {};
}
validateActions(actions);
const compiledActions = compileAnalyzeInput(actions);
const { updateIntervalInMs, resumeFrom } = realOptions, restOptions = __rest(realOptions, ["updateIntervalInMs", "resumeFrom"]);
const poller = new BeginAnalyzeActionsPoller({
client: this.client,
documents: realInputs,
actions: compiledActions,
options: restOptions,
resumeFrom: resumeFrom,
updateIntervalInMs: updateIntervalInMs
});
await poller.poll();
return poller;
}
}
function validateActions(actions) {
function validateActionType(actionList, actionType) {
var _a;
if (((_a = actionList === null || actionList === void 0 ? void 0 : actionList.length) !== null && _a !== void 0 ? _a : 0) > 1) {
throw new Error(`beginAnalyzeActions: Currently, the service can accept up to one action only for ${actionType} actions.`);
}
}
validateActionType(actions.analyzeSentimentActions, `analyzeSentiment`);
validateActionType(actions.extractKeyPhrasesActions, `extractKeyPhrases`);
validateActionType(actions.recognizeEntitiesActions, `recognizeEntities`);
validateActionType(actions.recognizeLinkedEntitiesActions, `recognizeLinkedEntities`);
validateActionType(actions.recognizePiiEntitiesActions, `recognizePiiEntities`);
}
/**
* @internal
*/
function compileAnalyzeInput(actions) {
var _a, _b, _c, _d, _e;
return {
entityRecognitionPiiTasks: (_a = actions.recognizePiiEntitiesActions) === null || _a === void 0 ? void 0 : _a.map(compose(setStrEncodingParam, compose(setCategoriesFilter, addParamsToTask))),
entityRecognitionTasks: (_b = actions.recognizeEntitiesActions) === null || _b === void 0 ? void 0 : _b.map(compose(setStrEncodingParam, addParamsToTask)),
keyPhraseExtractionTasks: (_c = actions.extractKeyPhrasesActions) === null || _c === void 0 ? void 0 : _c.map(addParamsToTask),
entityLinkingTasks: (_d = actions.recognizeLinkedEntitiesActions) === null || _d === void 0 ? void 0 : _d.map(compose(setStrEncodingParam, addParamsToTask)),
sentimentAnalysisTasks: (_e = actions.analyzeSentimentActions) === null || _e === void 0 ? void 0 : _e.map(compose(setStrEncodingParam, compose(setOpinionMining, addParamsToTask)))
};
}
function isStringArray(documents) {
return typeof documents[0] === "string";
}
/**
* @internal
*/
function convertToDetectLanguageInput(inputs, countryHint) {
if (countryHint === "none") {
countryHint = "";
}
return inputs.map((text, index) => {
return {
id: String(index),
countryHint,
text
};
});
}
/**
* @internal
*/
function convertToTextDocumentInput(inputs, language) {
return inputs.map((text, index) => {
return {
id: String(index),
language,
text
};
});
}
/**
* Creates the options the service expects for the analyze sentiment API from the user friendly ones.
* @param params - the user friendly parameters
* @internal
*/
function makeGeneratedAnalyzeSentimentOptions(params) {
return {
abortSignal: params.abortSignal,
opinionMining: params.includeOpinionMining,
includeStatistics: params.includeStatistics,
modelVersion: params.modelVersion,
requestOptions: params.requestOptions,
stringIndexType: setStrEncodingParamValue(params.stringIndexType),
tracingOptions: params.tracingOptions,
onResponse: params.onResponse,
serializerOptions: params.serializerOptions,
loggingOptOut: params.disableServiceLogs
};
}
/**
* Creates the options the service expects for the recognize pii entities API from the user friendly ones.
* @param params - the user friendly parameters
* @internal
*/
function makeGeneratedRecognizePiiEntitiesOptions(params) {
return {
abortSignal: params.abortSignal,
domain: params.domainFilter,
includeStatistics: params.includeStatistics,
modelVersion: params.modelVersion,
requestOptions: params.requestOptions,
stringIndexType: setStrEncodingParamValue(params.stringIndexType),
tracingOptions: params.tracingOptions,
piiCategories: params.categoriesFilter,
onResponse: params.onResponse,
serializerOptions: params.serializerOptions,
loggingOptOut: params.disableServiceLogs
};
}
/**
* Creates the options the service expects for the recognize entities API from the user friendly ones.
* @param params - the user friendly parameters
* @internal
*/
function makeGeneratedRecognizeCategorizedEntitiesOptions(params) {
return {
abortSignal: params.abortSignal,
includeStatistics: params.includeStatistics,
modelVersion: params.modelVersion,
requestOptions: params.requestOptions,
stringIndexType: setStrEncodingParamValue(params.stringIndexType),
tracingOptions: params.tracingOptions,
onResponse: params.onResponse,
serializerOptions: params.serializerOptions,
loggingOptOut: params.disableServiceLogs
};
}
/**
* Creates the options the service expects for the detect language API from the user friendly ones.
* @param params - the user friendly parameters
* @internal
*/
function makeGeneratedDetectLanguageOptions(params) {
return {
abortSignal: params.abortSignal,
includeStatistics: params.includeStatistics,
modelVersion: params.modelVersion,
requestOptions: params.requestOptions,
tracingOptions: params.tracingOptions,
onResponse: params.onResponse,
serializerOptions: params.serializerOptions,
loggingOptOut: params.disableServiceLogs
};
}
/**
* Creates the options the service expects for the extract key phrases API from the user friendly ones.
* @param params - the user friendly parameters
* @internal
*/
function makeGeneratedExtractKeyPhrasesOptions(params) {
return {
abortSignal: params.abortSignal,
includeStatistics: params.includeStatistics,
modelVersion: params.modelVersion,
requestOptions: params.requestOptions,
tracingOptions: params.tracingOptions,
onResponse: params.onResponse,
serializerOptions: params.serializerOptions,
loggingOptOut: params.disableServiceLogs
};
}
/**
* Creates the options the service expects for the recognize linked entities API from the user friendly ones.
* @param params - the user friendly parameters
* @internal
*/
function makeGeneratedRecognizeLinkingEntitiesOptions(params) {
return {
abortSignal: params.abortSignal,
includeStatistics: params.includeStatistics,
modelVersion: params.modelVersion,
requestOptions: params.requestOptions,
tracingOptions: params.tracingOptions,
onResponse: params.onResponse,
serializerOptions: params.serializerOptions,
loggingOptOut: params.disableServiceLogs,
stringIndexType: setStrEncodingParamValue(params.stringIndexType)
};
}
//# sourceMappingURL=textAnalyticsClient.js.map