UNPKG

@azure/ai-language-text

Version:

An isomorphic client library for the text analysis features in the Azure Cognitive Language Service.

383 lines 17.3 kB
// Copyright (c) Microsoft Corporation. // Licensed under the MIT license. import { __rest } from "tslib"; import { extractErrorPointerIndex, parseAssessmentIndex, parseHealthcareEntityIndex, sortResponseIdObjects, } from "./util"; import { RestError } from "@azure/core-rest-pipeline"; /** * Helper function for converting nested service error to the unified * TextAnalysisError */ function toTextAnalysisError(errorModel) { // Return the deepest error. if (errorModel.innererror !== undefined) { return toTextAnalysisError(errorModel.innererror); } return Object.assign({}, errorModel); } function makeTextAnalysisErrorResult(id, error) { return { id, error: toTextAnalysisError(error), }; } /** * combines successful and erroneous results into a single array of results and * sort them so that the IDs order match that of the input documents array. * @param ids - the array of input document IDs. * @param response - the response received from the service. * @param options - an options bag that includes functions to process the results. */ function transformDocumentResults(ids, response, options) { const { processError = makeTextAnalysisErrorResult, processSuccess } = options || {}; const successResults = processSuccess ? response.documents.map(processSuccess) : response.documents; const unsortedResults = successResults.concat(response.errors.map((error) => processError(error.id, error.error))); return sortResponseIdObjects(ids, unsortedResults); } function toLanguageDetectionResult(docIds, results) { return transformDocumentResults(docIds, results, { processSuccess: (_a) => { var { detectedLanguage } = _a, rest = __rest(_a, ["detectedLanguage"]); return (Object.assign({ primaryLanguage: detectedLanguage }, rest)); }, }); } function toPiiEntityRecognitionResult(docIds, results) { return transformDocumentResults(docIds, results); } function toSentimentAnalysisResult(docIds, results) { return transformDocumentResults(docIds, results, { processSuccess: (_a) => { var { sentences } = _a, rest = __rest(_a, ["sentences"]); return (Object.assign(Object.assign({}, rest), { sentences: sentences.map((sentence) => convertGeneratedSentenceSentiment(sentence, sentences)) })); }, }); } /** * Converts a sentence sentiment object returned by the service to another that * is user-friendly. * * @param sentence - The sentence sentiment object to be converted. * @param response - The entire response returned by the service. * @returns The user-friendly sentence sentiment object. * @internal */ function convertGeneratedSentenceSentiment(_a, sentences) { var _b; var { targets, assessments: _ } = _a, rest = __rest(_a, ["targets", "assessments"]); return Object.assign(Object.assign({}, rest), { opinions: (_b = targets === null || targets === void 0 ? void 0 : targets.map( // eslint-disable-next-line @typescript-eslint/no-shadow (_a) => { var { relations } = _a, rest = __rest(_a, ["relations"]); return ({ target: rest, assessments: relations .filter((relation) => relation.relationType === "assessment") .map((relation) => convertTargetRelationToAssessmentSentiment(relation, sentences)), }); })) !== null && _b !== void 0 ? _b : [] }); } /** * Converts a target relation object returned by the service to an assessment * sentiment object where JSON pointers in the former are realized in the * latter. * * @param targetRelation - The target relation object to be converted. * @param response - The entire response returned by the service. * @returns The user-friendly assessment sentiment object. * @internal */ function convertTargetRelationToAssessmentSentiment(targetRelation, sentences) { var _a; const assessmentPtr = targetRelation.ref; const assessmentIndex = parseAssessmentIndex(assessmentPtr); const assessment = (_a = sentences === null || sentences === void 0 ? void 0 : sentences[assessmentIndex.sentence].assessments) === null || _a === void 0 ? void 0 : _a[assessmentIndex.assessment]; if (assessment !== undefined) { return assessment; } else { throw new Error(`Pointer "${assessmentPtr}" is not a valid Assessment pointer`); } } function toEntityLinkingResult(docIds, results) { return transformDocumentResults(docIds, results); } function toKeyPhraseExtractionResult(docIds, results) { return transformDocumentResults(docIds, results); } function toEntityRecognitionResult(docIds, results) { return transformDocumentResults(docIds, results); } /** * @internal */ export function transformActionResult(actionName, docIds, response) { switch (response.kind) { case "EntityLinkingResults": { return toEntityLinkingResult(docIds, response.results); } case "EntityRecognitionResults": { return toEntityRecognitionResult(docIds, response.results); } case "KeyPhraseExtractionResults": { return toKeyPhraseExtractionResult(docIds, response.results); } case "PiiEntityRecognitionResults": { return toPiiEntityRecognitionResult(docIds, response.results); } case "SentimentAnalysisResults": { return toSentimentAnalysisResult(docIds, response.results); } case "LanguageDetectionResults": { return toLanguageDetectionResult(docIds, response.results); } default: { const __exhaust = response; throw new Error(`Unsupported results kind: ${__exhaust} for an action of type ${actionName}`); } } } function appendReadableErrorMessage(currentMessage, innerMessage) { let message = currentMessage; if (message.slice(-1) !== ".") { message = message + "."; } return message + " " + innerMessage; } /** * @internal * parses incoming errors from the service/ * @param error - the incoming error */ function transformError(errorResponse) { var _a; const strongErrorResponse = errorResponse; if (!strongErrorResponse.response) { throw errorResponse; } const topLevelError = (_a = strongErrorResponse.response.parsedBody) === null || _a === void 0 ? void 0 : _a.error; if (!topLevelError) return errorResponse; let errorMessage = topLevelError.message; let code = topLevelError.code; function unwrap(error) { const innerError = error.innererror; if (innerError) { if (innerError.message) { errorMessage = appendReadableErrorMessage(errorMessage, innerError.message); } if (innerError.code) { code = innerError.code; } return unwrap(innerError); } return error; } unwrap(topLevelError); return new RestError(errorMessage, { code, statusCode: strongErrorResponse.statusCode, }); } export async function throwError(p) { try { return await p; } catch (e) { throw transformError(e); } } function toHealthcareResult(docIds, results) { function makeHealthcareEntity(entity) { const { dataSources } = entity, rest = __rest(entity, ["dataSources"]); return Object.assign({ dataSources: dataSources !== null && dataSources !== void 0 ? dataSources : [] }, rest); } function makeHealthcareRelation(entities) { return ({ entities: generatedEntities, relationType, confidenceScore, }) => ({ relationType: relationType, confidenceScore, roles: generatedEntities.map((role) => ({ entity: entities[parseHealthcareEntityIndex(role.ref)], name: role.role, })), }); } return transformDocumentResults(docIds, results, { processSuccess: (_a) => { var { entities, relations } = _a, rest = __rest(_a, ["entities", "relations"]); const newEntities = entities.map(makeHealthcareEntity); return Object.assign({ entities: newEntities, entityRelations: relations.map(makeHealthcareRelation(newEntities)) }, rest); }, }); } /** * @internal */ export function transformAnalyzeBatchResults(docIds, response = [], errors = []) { const errorMap = toIndexErrorMap(errors); return response.map((actionData, idx) => { const { lastUpdateDateTime: completedOn, actionName, kind: resultKind } = actionData; const error = errorMap.get(idx); switch (resultKind) { case "SentimentAnalysisLROResults": { const kind = "SentimentAnalysis"; if (actionData.status === "failed") { return returnErrorTask(kind, error, completedOn); } const { results } = actionData; const { modelVersion, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind, results: toSentimentAnalysisResult(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { modelVersion }); } case "EntityRecognitionLROResults": { const kind = "EntityRecognition"; if (actionData.status === "failed") { return returnErrorTask(kind, error, completedOn); } const { results } = actionData; const { modelVersion, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind: "EntityRecognition", results: toEntityRecognitionResult(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { modelVersion }); } case "PiiEntityRecognitionLROResults": { const kind = "PiiEntityRecognition"; if (actionData.status === "failed") { return returnErrorTask(kind, error, completedOn); } const { results } = actionData; const { modelVersion, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind, results: toPiiEntityRecognitionResult(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { modelVersion }); } case "KeyPhraseExtractionLROResults": { const kind = "KeyPhraseExtraction"; if (actionData.status === "failed") { return returnErrorTask(kind, error, completedOn); } const { results } = actionData; const { modelVersion, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind, results: toKeyPhraseExtractionResult(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { modelVersion }); } case "EntityLinkingLROResults": { const kind = "EntityLinking"; if (actionData.status === "failed") { return returnErrorTask(kind, error, completedOn); } const { results } = actionData; const { modelVersion, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind, results: toEntityLinkingResult(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { modelVersion }); } case "HealthcareLROResults": { const kind = "Healthcare"; if (actionData.status === "failed") { return returnErrorTask(kind, error, completedOn); } const { results } = actionData; const { modelVersion, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind, results: toHealthcareResult(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { modelVersion }); } case "CustomEntityRecognitionLROResults": { const kind = "CustomEntityRecognition"; if (actionData.status === "failed") { return returnErrorCustomTask(kind, error, completedOn); } const { results } = actionData; const { deploymentName, projectName, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind, results: transformDocumentResults(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { deploymentName, projectName }); } case "CustomSingleLabelClassificationLROResults": { const kind = "CustomSingleLabelClassification"; if (actionData.status === "failed") { return returnErrorCustomTask(kind, error, completedOn); } const { results } = actionData; const { deploymentName, projectName, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind, results: transformDocumentResults(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { deploymentName, projectName }); } case "CustomMultiLabelClassificationLROResults": { const kind = "CustomMultiLabelClassification"; if (actionData.status === "failed") { return returnErrorCustomTask(kind, error, completedOn); } const { results } = actionData; const { deploymentName, projectName, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind, results: transformDocumentResults(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { deploymentName, projectName }); } case "ExtractiveSummarizationLROResults": { const kind = "ExtractiveSummarization"; if (actionData.status === "failed") { return returnErrorTask(kind, error, completedOn); } const { results } = actionData; const { modelVersion, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind: "ExtractiveSummarization", results: transformDocumentResults(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { modelVersion }); } case "AbstractiveSummarizationLROResults": { const kind = "AbstractiveSummarization"; if (actionData.status === "failed") { return returnErrorTask(kind, error, completedOn); } const { results } = actionData; const { modelVersion, statistics } = results; return Object.assign(Object.assign(Object.assign({ kind: "AbstractiveSummarization", results: transformDocumentResults(docIds, results), completedOn }, (actionName ? { actionName } : {})), (statistics ? { statistics } : {})), { modelVersion }); } default: { throw new Error(`Unsupported results kind: ${resultKind}`); } } }); } /** * @internal * Transform a list of error into index and error Map */ function toIndexErrorMap(errors) { const errorMap = new Map(); for (const error of errors) { const position = extractErrorPointerIndex(error); const { target } = error, errorWithoutTarget = __rest(error, ["target"]); errorMap.set(position, toTextAnalysisError(errorWithoutTarget)); } return errorMap; } /** * Return the error for non-custom task * * @param kind - non custom task kind * @param error - error returned from the service * @param failedOn - the LastUpdateDateTime from the service * @returns - AnalyzeBatchResult with error */ function returnErrorTask(kind, error, failedOn) { if (!error) { throw new Error("Unexpected response from service - no errors for missing action results."); } return { kind, modelVersion: "", failedOn, error, }; } /** * Return the error for non-custom task * * @param kind - non custom task kind * @param error - error returned from the service * @param failedOn - the LastUpdateDateTime from the service * @returns AnalyzeBatchResult for custom task with error */ function returnErrorCustomTask(kind, error, failedOn) { if (!error) { throw new Error("Unexpected response from service - no errors for missing action results."); } return { kind, projectName: "", deploymentName: "", failedOn, error, }; } //# sourceMappingURL=transforms.js.map