@aws-amplify/predictions 5.5.6-api-v6-models.b3abc9b.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/README.md +3 -0
  2. package/lib/Predictions.d.ts +11 -45
  3. package/lib/Predictions.js +24 -132
  4. package/lib/errors/PredictionsError.d.ts +4 -0
  5. package/lib/errors/PredictionsError.js +15 -0
  6. package/lib/errors/types/validation.d.ts +14 -0
  7. package/lib/errors/types/validation.js +50 -0
  8. package/lib/errors/utils/assertValidationError.d.ts +2 -0
  9. package/lib/errors/utils/assertValidationError.js +14 -0
  10. package/lib/index.d.ts +2 -4
  11. package/lib/index.js +2 -9
  12. package/{lib-esm/Providers → lib/providers}/AmazonAIConvertPredictionsProvider.d.ts +6 -7
  13. package/lib/providers/AmazonAIConvertPredictionsProvider.js +307 -0
  14. package/lib/{Providers → providers}/AmazonAIIdentifyPredictionsProvider.d.ts +5 -6
  15. package/lib/providers/AmazonAIIdentifyPredictionsProvider.js +334 -0
  16. package/lib/{Providers → providers}/AmazonAIInterpretPredictionsProvider.d.ts +3 -4
  17. package/lib/providers/AmazonAIInterpretPredictionsProvider.js +208 -0
  18. package/lib/providers/IdentifyTextUtils.d.ts +16 -0
  19. package/lib/{Providers → providers}/IdentifyTextUtils.js +97 -148
  20. package/lib/{Providers → providers}/Utils.d.ts +2 -2
  21. package/lib/{Providers → providers}/Utils.js +11 -12
  22. package/lib/{Providers → providers}/index.d.ts +1 -2
  23. package/lib/providers/index.js +11 -0
  24. package/lib/tsconfig.tsbuildinfo +1 -0
  25. package/lib/types/AWSTypes.d.ts +8 -9
  26. package/lib/types/AWSTypes.js +0 -1
  27. package/lib/types/Predictions.d.ts +63 -59
  28. package/lib/types/Predictions.js +41 -28
  29. package/lib/types/index.js +1 -2
  30. package/lib-esm/Predictions.d.ts +11 -45
  31. package/lib-esm/Predictions.js +23 -133
  32. package/lib-esm/errors/PredictionsError.d.ts +4 -0
  33. package/lib-esm/errors/PredictionsError.js +11 -0
  34. package/lib-esm/errors/types/validation.d.ts +14 -0
  35. package/lib-esm/errors/types/validation.js +47 -0
  36. package/lib-esm/errors/utils/assertValidationError.d.ts +2 -0
  37. package/lib-esm/errors/utils/assertValidationError.js +10 -0
  38. package/lib-esm/index.d.ts +2 -4
  39. package/lib-esm/index.js +1 -5
  40. package/{lib/Providers → lib-esm/providers}/AmazonAIConvertPredictionsProvider.d.ts +6 -7
  41. package/lib-esm/providers/AmazonAIConvertPredictionsProvider.js +303 -0
  42. package/lib-esm/{Providers → providers}/AmazonAIIdentifyPredictionsProvider.d.ts +5 -6
  43. package/lib-esm/providers/AmazonAIIdentifyPredictionsProvider.js +330 -0
  44. package/lib-esm/{Providers → providers}/AmazonAIInterpretPredictionsProvider.d.ts +3 -4
  45. package/lib-esm/providers/AmazonAIInterpretPredictionsProvider.js +204 -0
  46. package/lib-esm/providers/IdentifyTextUtils.d.ts +16 -0
  47. package/lib-esm/providers/IdentifyTextUtils.js +264 -0
  48. package/lib-esm/{Providers → providers}/Utils.d.ts +2 -2
  49. package/lib-esm/{Providers → providers}/Utils.js +10 -12
  50. package/lib-esm/{Providers → providers}/index.d.ts +1 -2
  51. package/lib-esm/{Providers → providers}/index.js +1 -3
  52. package/lib-esm/tsconfig.tsbuildinfo +1 -0
  53. package/lib-esm/types/AWSTypes.d.ts +8 -9
  54. package/lib-esm/types/AWSTypes.js +1 -1
  55. package/lib-esm/types/Predictions.d.ts +63 -59
  56. package/lib-esm/types/Predictions.js +34 -27
  57. package/lib-esm/types/index.js +0 -1
  58. package/package.json +39 -48
  59. package/src/Predictions.ts +33 -220
  60. package/src/errors/PredictionsError.ts +16 -0
  61. package/src/errors/types/validation.ts +51 -0
  62. package/src/errors/utils/assertValidationError.ts +18 -0
  63. package/src/index.ts +16 -16
  64. package/src/{Providers → providers}/AmazonAIConvertPredictionsProvider.ts +210 -171
  65. package/src/{Providers → providers}/AmazonAIIdentifyPredictionsProvider.ts +244 -246
  66. package/src/providers/AmazonAIInterpretPredictionsProvider.ts +293 -0
  67. package/src/{Providers → providers}/IdentifyTextUtils.ts +69 -52
  68. package/src/{Providers → providers}/Utils.ts +2 -2
  69. package/src/{Providers → providers}/index.ts +0 -2
  70. package/src/types/AWSTypes.ts +5 -6
  71. package/src/types/Predictions.ts +107 -62
  72. package/lib/.tsbuildinfo +0 -3
  73. package/lib/Predictions.js.map +0 -1
  74. package/lib/Providers/AmazonAIConvertPredictionsProvider.js +0 -377
  75. package/lib/Providers/AmazonAIConvertPredictionsProvider.js.map +0 -1
  76. package/lib/Providers/AmazonAIIdentifyPredictionsProvider.js +0 -441
  77. package/lib/Providers/AmazonAIIdentifyPredictionsProvider.js.map +0 -1
  78. package/lib/Providers/AmazonAIInterpretPredictionsProvider.js +0 -321
  79. package/lib/Providers/AmazonAIInterpretPredictionsProvider.js.map +0 -1
  80. package/lib/Providers/AmazonAIPredictionsProvider.d.ts +0 -14
  81. package/lib/Providers/AmazonAIPredictionsProvider.js +0 -43
  82. package/lib/Providers/AmazonAIPredictionsProvider.js.map +0 -1
  83. package/lib/Providers/IdentifyTextUtils.d.ts +0 -40
  84. package/lib/Providers/IdentifyTextUtils.js.map +0 -1
  85. package/lib/Providers/Utils.js.map +0 -1
  86. package/lib/Providers/index.js +0 -13
  87. package/lib/Providers/index.js.map +0 -1
  88. package/lib/index.js.map +0 -1
  89. package/lib/types/AWSTypes.js.map +0 -1
  90. package/lib/types/Predictions.js.map +0 -1
  91. package/lib/types/Providers/AbstractConvertPredictionsProvider.d.ts +0 -9
  92. package/lib/types/Providers/AbstractConvertPredictionsProvider.js +0 -44
  93. package/lib/types/Providers/AbstractConvertPredictionsProvider.js.map +0 -1
  94. package/lib/types/Providers/AbstractIdentifyPredictionsProvider.d.ts +0 -9
  95. package/lib/types/Providers/AbstractIdentifyPredictionsProvider.js +0 -44
  96. package/lib/types/Providers/AbstractIdentifyPredictionsProvider.js.map +0 -1
  97. package/lib/types/Providers/AbstractInterpretPredictionsProvider.d.ts +0 -7
  98. package/lib/types/Providers/AbstractInterpretPredictionsProvider.js +0 -27
  99. package/lib/types/Providers/AbstractInterpretPredictionsProvider.js.map +0 -1
  100. package/lib/types/Providers/AbstractPredictionsProvider.d.ts +0 -7
  101. package/lib/types/Providers/AbstractPredictionsProvider.js +0 -16
  102. package/lib/types/Providers/AbstractPredictionsProvider.js.map +0 -1
  103. package/lib/types/Providers/index.d.ts +0 -4
  104. package/lib/types/Providers/index.js +0 -10
  105. package/lib/types/Providers/index.js.map +0 -1
  106. package/lib/types/index.js.map +0 -1
  107. package/lib-esm/.tsbuildinfo +0 -3
  108. package/lib-esm/Predictions.js.map +0 -1
  109. package/lib-esm/Providers/AmazonAIConvertPredictionsProvider.js +0 -375
  110. package/lib-esm/Providers/AmazonAIConvertPredictionsProvider.js.map +0 -1
  111. package/lib-esm/Providers/AmazonAIIdentifyPredictionsProvider.js +0 -439
  112. package/lib-esm/Providers/AmazonAIIdentifyPredictionsProvider.js.map +0 -1
  113. package/lib-esm/Providers/AmazonAIInterpretPredictionsProvider.js +0 -319
  114. package/lib-esm/Providers/AmazonAIInterpretPredictionsProvider.js.map +0 -1
  115. package/lib-esm/Providers/AmazonAIPredictionsProvider.d.ts +0 -14
  116. package/lib-esm/Providers/AmazonAIPredictionsProvider.js +0 -41
  117. package/lib-esm/Providers/AmazonAIPredictionsProvider.js.map +0 -1
  118. package/lib-esm/Providers/IdentifyTextUtils.d.ts +0 -40
  119. package/lib-esm/Providers/IdentifyTextUtils.js +0 -313
  120. package/lib-esm/Providers/IdentifyTextUtils.js.map +0 -1
  121. package/lib-esm/Providers/Utils.js.map +0 -1
  122. package/lib-esm/Providers/index.js.map +0 -1
  123. package/lib-esm/index.js.map +0 -1
  124. package/lib-esm/types/AWSTypes.js.map +0 -1
  125. package/lib-esm/types/Predictions.js.map +0 -1
  126. package/lib-esm/types/Providers/AbstractConvertPredictionsProvider.d.ts +0 -9
  127. package/lib-esm/types/Providers/AbstractConvertPredictionsProvider.js +0 -42
  128. package/lib-esm/types/Providers/AbstractConvertPredictionsProvider.js.map +0 -1
  129. package/lib-esm/types/Providers/AbstractIdentifyPredictionsProvider.d.ts +0 -9
  130. package/lib-esm/types/Providers/AbstractIdentifyPredictionsProvider.js +0 -42
  131. package/lib-esm/types/Providers/AbstractIdentifyPredictionsProvider.js.map +0 -1
  132. package/lib-esm/types/Providers/AbstractInterpretPredictionsProvider.d.ts +0 -7
  133. package/lib-esm/types/Providers/AbstractInterpretPredictionsProvider.js +0 -25
  134. package/lib-esm/types/Providers/AbstractInterpretPredictionsProvider.js.map +0 -1
  135. package/lib-esm/types/Providers/AbstractPredictionsProvider.d.ts +0 -7
  136. package/lib-esm/types/Providers/AbstractPredictionsProvider.js +0 -14
  137. package/lib-esm/types/Providers/AbstractPredictionsProvider.js.map +0 -1
  138. package/lib-esm/types/Providers/index.d.ts +0 -4
  139. package/lib-esm/types/Providers/index.js +0 -7
  140. package/lib-esm/types/Providers/index.js.map +0 -1
  141. package/lib-esm/types/index.js.map +0 -1
  142. package/src/Providers/AmazonAIInterpretPredictionsProvider.ts +0 -281
  143. package/src/Providers/AmazonAIPredictionsProvider.ts +0 -69
  144. package/src/types/Providers/AbstractConvertPredictionsProvider.ts +0 -55
  145. package/src/types/Providers/AbstractIdentifyPredictionsProvider.ts +0 -57
  146. package/src/types/Providers/AbstractInterpretPredictionsProvider.ts +0 -26
  147. package/src/types/Providers/AbstractPredictionsProvider.ts +0 -20
  148. package/src/types/Providers/index.ts +0 -6
@@ -0,0 +1,330 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { Amplify, ConsoleLogger as Logger, fetchAuthSession, } from '@aws-amplify/core';
4
+ import { Category, PredictionsAction, getAmplifyUserAgentObject, } from '@aws-amplify/core/internals/utils';
5
+ import { getUrl } from '@aws-amplify/storage';
6
+ import { DetectFacesCommand, DetectLabelsCommand, DetectModerationLabelsCommand, DetectTextCommand, RecognizeCelebritiesCommand, RekognitionClient, SearchFacesByImageCommand, } from '@aws-sdk/client-rekognition';
7
+ import { AnalyzeDocumentCommand, DetectDocumentTextCommand, TextractClient, } from '@aws-sdk/client-textract';
8
+ import { PredictionsValidationErrorCode } from '../errors/types/validation';
9
+ import { assertValidationError } from '../errors/utils/assertValidationError';
10
+ import { isFileSource, isIdentifyBytesSource, isIdentifyCelebrities, isIdentifyFromCollection, isIdentifyLabelsInput, isIdentifyTextInput, isStorageSource, isValidIdentifyInput, } from '../types';
11
+ import { categorizeRekognitionBlocks, categorizeTextractBlocks, } from './IdentifyTextUtils';
12
+ import { blobToArrayBuffer, makeCamelCase, makeCamelCaseArray } from './Utils';
13
+ const logger = new Logger('AmazonAIIdentifyPredictionsProvider');
14
+ export class AmazonAIIdentifyPredictionsProvider {
15
+ getProviderName() {
16
+ return 'AmazonAIIdentifyPredictionsProvider';
17
+ }
18
+ identify(input) {
19
+ assertValidationError(isValidIdentifyInput(input), PredictionsValidationErrorCode.InvalidInput);
20
+ if (isIdentifyTextInput(input)) {
21
+ logger.debug('identifyText');
22
+ return this.identifyText(input);
23
+ }
24
+ else if (isIdentifyLabelsInput(input)) {
25
+ logger.debug('identifyLabels');
26
+ return this.identifyLabels(input);
27
+ }
28
+ else {
29
+ logger.debug('identifyEntities');
30
+ return this.identifyEntities(input);
31
+ }
32
+ }
33
+ /**
34
+ * Verify user input source and converts it into source object readable by Rekognition and Textract.
35
+ * Note that Rekognition and Textract use the same source interface, so we need not worry about types.
36
+ * @param {IdentifySource} source - User input source that directs to the object user wants
37
+ * to identify (storage, file, or bytes).
38
+ * @return {Promise<Image>} - Promise resolving to the converted source object.
39
+ */
40
+ configureSource(source) {
41
+ return new Promise((res, rej) => {
42
+ if (isStorageSource(source)) {
43
+ const storageConfig = {
44
+ accessLevel: source.level,
45
+ targetIdentityId: source.identityId,
46
+ };
47
+ getUrl({ key: source.key, options: storageConfig })
48
+ .then(value => {
49
+ const parser = /https:\/\/([a-zA-Z0-9%\-_.]+)\.s3\.[A-Za-z0-9%\-._~]+\/([a-zA-Z0-9%\-._~/]+)\?/;
50
+ const parsedURL = value.url.toString().match(parser) ?? '';
51
+ if (parsedURL.length < 3)
52
+ rej('Invalid S3 key was given.');
53
+ res({
54
+ S3Object: {
55
+ Bucket: parsedURL[1],
56
+ Name: decodeURIComponent(parsedURL[2]),
57
+ },
58
+ });
59
+ })
60
+ .catch(err => rej(err));
61
+ }
62
+ else if (isFileSource(source)) {
63
+ blobToArrayBuffer(source.file)
64
+ .then(buffer => {
65
+ res({ Bytes: new Uint8Array(buffer) });
66
+ })
67
+ .catch(err => rej(err));
68
+ }
69
+ else if (isIdentifyBytesSource(source)) {
70
+ const bytes = source.bytes;
71
+ if (bytes instanceof Blob) {
72
+ blobToArrayBuffer(bytes)
73
+ .then(buffer => {
74
+ res({ Bytes: new Uint8Array(buffer) });
75
+ })
76
+ .catch(err => rej(err));
77
+ }
78
+ if (bytes instanceof ArrayBuffer || bytes instanceof Buffer) {
79
+ res({ Bytes: new Uint8Array(bytes) });
80
+ }
81
+ // everything else can be directly passed to Rekognition / Textract.
82
+ res({ Bytes: bytes });
83
+ }
84
+ else {
85
+ rej('Input source is not configured correctly.');
86
+ }
87
+ });
88
+ }
89
+ /**
90
+ * Recognize text from real-world images and documents (plain text, forms and tables). Detects text in the input
91
+ * image and converts it into machine-readable text.
92
+ * @param {IdentifySource} source - Object containing the source image and feature types to analyze.
93
+ * @return {Promise<IdentifyTextOutput>} - Promise resolving to object containing identified texts.
94
+ */
95
+ async identifyText(input) {
96
+ const { credentials } = await fetchAuthSession();
97
+ assertValidationError(!!credentials, PredictionsValidationErrorCode.NoCredentials);
98
+ const { identifyText = {} } = Amplify.getConfig().Predictions?.identify ?? {};
99
+ const { region = '', defaults = {} } = identifyText;
100
+ const { format: configFormat = 'PLAIN' } = defaults;
101
+ this.rekognitionClient = new RekognitionClient({
102
+ region,
103
+ credentials,
104
+ customUserAgent: _getPredictionsIdentifyAmplifyUserAgent(),
105
+ });
106
+ this.textractClient = new TextractClient({
107
+ region,
108
+ credentials,
109
+ customUserAgent: _getPredictionsIdentifyAmplifyUserAgent(),
110
+ });
111
+ let inputDocument;
112
+ inputDocument = await this.configureSource(input.text?.source);
113
+ // get default value if format isn't specified in the input.
114
+ const format = input.text?.format ?? configFormat;
115
+ const featureTypes = []; // structures we want to analyze (e.g. [TABLES, FORMS]).
116
+ if (format === 'FORM' || format === 'ALL')
117
+ featureTypes.push('FORMS');
118
+ if (format === 'TABLE' || format === 'ALL')
119
+ featureTypes.push('TABLES');
120
+ if (featureTypes.length === 0) {
121
+ /**
122
+ * Empty featureTypes indicates that we will identify plain text. We will use rekognition (suitable
123
+ * for everyday images but has 50 word limit) first and see if reaches its word limit. If it does, then
124
+ * we call textract and use the data that identify more words.
125
+ */
126
+ const textractParam = {
127
+ Document: inputDocument,
128
+ };
129
+ const rekognitionParam = {
130
+ Image: inputDocument,
131
+ };
132
+ const detectTextCommand = new DetectTextCommand(rekognitionParam);
133
+ const rekognitionData = await this.rekognitionClient.send(detectTextCommand);
134
+ const rekognitionResponse = categorizeRekognitionBlocks(rekognitionData.TextDetections);
135
+ if (rekognitionResponse.text.words.length < 50) {
136
+ // did not hit the word limit, return the data
137
+ return rekognitionResponse;
138
+ }
139
+ const detectDocumentTextCommand = new DetectDocumentTextCommand(textractParam);
140
+ const { Blocks } = await this.textractClient.send(detectDocumentTextCommand);
141
+ if ((rekognitionData.TextDetections?.length ?? 0) > (Blocks?.length ?? 0)) {
142
+ return rekognitionResponse;
143
+ }
144
+ return categorizeTextractBlocks(Blocks);
145
+ }
146
+ else {
147
+ const param = {
148
+ Document: inputDocument,
149
+ FeatureTypes: featureTypes,
150
+ };
151
+ const analyzeDocumentCommand = new AnalyzeDocumentCommand(param);
152
+ const { Blocks } = await this.textractClient.send(analyzeDocumentCommand);
153
+ return categorizeTextractBlocks(Blocks);
154
+ }
155
+ }
156
+ /**
157
+ * Identify instances of real world entities from an image and if it contains unsafe content.
158
+ * @param {IdentifyLabelsInput} input - Object containing the source image and entity type to identify.
159
+ * @return {Promise<IdentifyLabelsOutput>} - Promise resolving to an array of identified entities.
160
+ */
161
+ async identifyLabels(input) {
162
+ const { credentials } = await fetchAuthSession();
163
+ assertValidationError(!!credentials, PredictionsValidationErrorCode.NoCredentials);
164
+ const { identifyLabels = {} } = Amplify.getConfig().Predictions?.identify ?? {};
165
+ const { region = '', defaults = {} } = identifyLabels;
166
+ const { type = 'LABELS' } = defaults;
167
+ this.rekognitionClient = new RekognitionClient({
168
+ region,
169
+ credentials,
170
+ customUserAgent: _getPredictionsIdentifyAmplifyUserAgent(),
171
+ });
172
+ const inputImage = await this.configureSource(input.labels?.source);
173
+ const param = { Image: inputImage };
174
+ const servicePromises = [];
175
+ // get default argument
176
+ const entityType = input.labels?.type ?? type;
177
+ if (entityType === 'LABELS' || entityType === 'ALL') {
178
+ servicePromises.push(this.detectLabels(param));
179
+ }
180
+ if (entityType === 'UNSAFE' || entityType === 'ALL') {
181
+ servicePromises.push(this.detectModerationLabels(param));
182
+ }
183
+ return Promise.all(servicePromises).then(data => {
184
+ let identifyResult = {};
185
+ // concatenate resolved promises to a single object
186
+ data.forEach(val => {
187
+ identifyResult = { ...identifyResult, ...val };
188
+ });
189
+ return identifyResult;
190
+ });
191
+ }
192
+ /**
193
+ * Calls Rekognition.detectLabels and organizes the returned data.
194
+ * @param {DetectLabelsInput} param - parameter to be passed onto Rekognition
195
+ * @return {Promise<IdentifyLabelsOutput>} - Promise resolving to organized detectLabels response.
196
+ */
197
+ async detectLabels(param) {
198
+ const detectLabelsCommand = new DetectLabelsCommand(param);
199
+ const data = await this.rekognitionClient.send(detectLabelsCommand);
200
+ if (!data.Labels)
201
+ return {}; // no image was detected
202
+ const detectLabelData = data.Labels.map(label => {
203
+ const boxes = label.Instances?.map(instance => makeCamelCase(instance.BoundingBox)) || [];
204
+ return {
205
+ name: label.Name,
206
+ boundingBoxes: boxes,
207
+ metadata: {
208
+ confidence: label.Confidence,
209
+ parents: makeCamelCaseArray(label.Parents),
210
+ },
211
+ };
212
+ });
213
+ return { labels: detectLabelData };
214
+ }
215
+ /**
216
+ * Calls Rekognition.detectModerationLabels and organizes the returned data.
217
+ * @param {Rekognition.DetectLabelsRequest} param - Parameter to be passed onto Rekognition
218
+ * @return {Promise<IdentifyLabelsOutput>} - Promise resolving to organized detectModerationLabels response.
219
+ */
220
+ async detectModerationLabels(param) {
221
+ const detectModerationLabelsCommand = new DetectModerationLabelsCommand(param);
222
+ const data = await this.rekognitionClient.send(detectModerationLabelsCommand);
223
+ if (data.ModerationLabels?.length !== 0) {
224
+ return { unsafe: 'YES' };
225
+ }
226
+ else {
227
+ return { unsafe: 'NO' };
228
+ }
229
+ }
230
+ /**
231
+ * Identify faces within an image that is provided as input, and match faces from a collection
232
+ * or identify celebrities.
233
+ * @param {IdentifyEntityInput} input - object containing the source image and face match options.
234
+ * @return {Promise<IdentifyEntityOutput>} Promise resolving to identify results.
235
+ */
236
+ async identifyEntities(input) {
237
+ const { credentials } = await fetchAuthSession();
238
+ assertValidationError(!!credentials, PredictionsValidationErrorCode.NoCredentials);
239
+ const { identifyEntities = {} } = Amplify.getConfig().Predictions?.identify ?? {};
240
+ const { region = '', celebrityDetectionEnabled = false, defaults = {}, } = identifyEntities;
241
+ const { collectionId: collectionIdConfig = '', maxEntities: maxFacesConfig = 50, } = defaults;
242
+ // default arguments
243
+ this.rekognitionClient = new RekognitionClient({
244
+ region,
245
+ credentials,
246
+ customUserAgent: _getPredictionsIdentifyAmplifyUserAgent(),
247
+ });
248
+ const inputImage = await this.configureSource(input.entities?.source);
249
+ const param = { Attributes: ['ALL'], Image: inputImage };
250
+ if (isIdentifyCelebrities(input.entities) &&
251
+ input.entities.celebrityDetection) {
252
+ assertValidationError(celebrityDetectionEnabled, PredictionsValidationErrorCode.CelebrityDetectionNotEnabled);
253
+ const recognizeCelebritiesCommand = new RecognizeCelebritiesCommand(param);
254
+ const data = await this.rekognitionClient.send(recognizeCelebritiesCommand);
255
+ const faces = data.CelebrityFaces?.map(celebrity => ({
256
+ boundingBox: makeCamelCase(celebrity.Face?.BoundingBox),
257
+ landmarks: makeCamelCaseArray(celebrity.Face?.Landmarks),
258
+ metadata: {
259
+ ...makeCamelCase(celebrity, ['Id', 'Name', 'Urls']),
260
+ pose: makeCamelCase(celebrity.Face?.Pose),
261
+ },
262
+ })) ?? [];
263
+ return { entities: faces };
264
+ }
265
+ else if (isIdentifyFromCollection(input.entities) &&
266
+ input.entities.collection) {
267
+ const { collectionId = collectionIdConfig, maxEntities: maxFaces = maxFacesConfig, } = input.entities;
268
+ // Concatenate additional parameters
269
+ const updatedParam = {
270
+ ...param,
271
+ CollectionId: collectionId,
272
+ MaxFaces: maxFaces,
273
+ };
274
+ const searchFacesByImageCommand = new SearchFacesByImageCommand(updatedParam);
275
+ const data = await this.rekognitionClient.send(searchFacesByImageCommand);
276
+ const faces = data.FaceMatches?.map(match => {
277
+ const externalImageId = match.Face?.ExternalImageId
278
+ ? this.decodeExternalImageId(match.Face.ExternalImageId)
279
+ : undefined;
280
+ return {
281
+ boundingBox: makeCamelCase(match.Face?.BoundingBox),
282
+ metadata: {
283
+ externalImageId,
284
+ similarity: match.Similarity,
285
+ },
286
+ };
287
+ }) ?? [];
288
+ return { entities: faces };
289
+ }
290
+ else {
291
+ const detectFacesCommand = new DetectFacesCommand(param);
292
+ const data = await this.rekognitionClient.send(detectFacesCommand);
293
+ const faces = data.FaceDetails?.map(detail => {
294
+ // face attributes keys we want to extract from Rekognition's response
295
+ const attributeKeys = [
296
+ 'Smile',
297
+ 'Eyeglasses',
298
+ 'Sunglasses',
299
+ 'Gender',
300
+ 'Beard',
301
+ 'Mustache',
302
+ 'EyesOpen',
303
+ 'MouthOpen',
304
+ ];
305
+ const faceAttributes = makeCamelCase(detail, attributeKeys);
306
+ faceAttributes.emotions = detail.Emotions?.map(emotion => emotion.Type);
307
+ return {
308
+ boundingBox: makeCamelCase(detail.BoundingBox),
309
+ landmarks: makeCamelCaseArray(detail.Landmarks),
310
+ ageRange: makeCamelCase(detail.AgeRange),
311
+ attributes: faceAttributes,
312
+ metadata: {
313
+ confidence: detail.Confidence,
314
+ pose: makeCamelCase(detail.Pose),
315
+ },
316
+ };
317
+ }) ?? [];
318
+ return { entities: faces };
319
+ }
320
+ }
321
+ decodeExternalImageId(externalImageId) {
322
+ return ('' + externalImageId).replace(/::/g, '/');
323
+ }
324
+ }
325
+ function _getPredictionsIdentifyAmplifyUserAgent() {
326
+ return getAmplifyUserAgentObject({
327
+ category: Category.Predictions,
328
+ action: PredictionsAction.Identify,
329
+ });
330
+ }
@@ -1,9 +1,8 @@
1
- import { AbstractInterpretPredictionsProvider } from '../types/Providers';
2
1
  import { InterpretTextInput, InterpretTextOutput } from '../types';
3
- export declare class AmazonAIInterpretPredictionsProvider extends AbstractInterpretPredictionsProvider {
4
- private comprehendClient;
5
- constructor();
2
+ export declare class AmazonAIInterpretPredictionsProvider {
3
+ private comprehendClient?;
6
4
  getProviderName(): string;
5
+ interpret(input: InterpretTextInput): Promise<InterpretTextOutput>;
7
6
  interpretText(input: InterpretTextInput): Promise<InterpretTextOutput>;
8
7
  private detectKeyPhrases;
9
8
  private detectSyntax;
@@ -0,0 +1,204 @@
1
+ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2
+ // SPDX-License-Identifier: Apache-2.0
3
+ import { Amplify, fetchAuthSession } from '@aws-amplify/core';
4
+ import { Category, PredictionsAction, getAmplifyUserAgentObject, } from '@aws-amplify/core/internals/utils';
5
+ import { ComprehendClient, DetectDominantLanguageCommand, DetectEntitiesCommand, DetectKeyPhrasesCommand, DetectSentimentCommand, DetectSyntaxCommand, } from '@aws-sdk/client-comprehend';
6
+ import { PredictionsValidationErrorCode } from '../errors/types/validation';
7
+ import { assertValidationError } from '../errors/utils/assertValidationError';
8
+ import { isInterpretTextOthers, isValidInterpretInput, } from '../types';
9
+ export class AmazonAIInterpretPredictionsProvider {
10
+ getProviderName() {
11
+ return 'AmazonAIInterpretPredictionsProvider';
12
+ }
13
+ interpret(input) {
14
+ assertValidationError(isValidInterpretInput(input), PredictionsValidationErrorCode.InvalidInput);
15
+ return this.interpretText(input);
16
+ }
17
+ async interpretText(input) {
18
+ const { credentials } = await fetchAuthSession();
19
+ assertValidationError(!!credentials, PredictionsValidationErrorCode.NoCredentials);
20
+ const { interpretText = {} } = Amplify.getConfig().Predictions?.interpret ?? {};
21
+ const { region = '', defaults = {} } = interpretText;
22
+ const { type: defaultType = '' } = defaults;
23
+ const { text: textSource } = input;
24
+ const { source, type = defaultType } = textSource;
25
+ const { text } = source;
26
+ let language;
27
+ if (isInterpretTextOthers(textSource)) {
28
+ language = textSource.source.language;
29
+ }
30
+ this.comprehendClient = new ComprehendClient({
31
+ credentials,
32
+ region,
33
+ customUserAgent: getAmplifyUserAgentObject({
34
+ category: Category.Predictions,
35
+ action: PredictionsAction.Interpret,
36
+ }),
37
+ });
38
+ const doAll = type === 'all';
39
+ let languageCode = language;
40
+ if (doAll || type === 'language') {
41
+ const languageDetectionParams = {
42
+ Text: text,
43
+ };
44
+ languageCode = await this.detectLanguage(languageDetectionParams);
45
+ }
46
+ let entitiesPromise;
47
+ if (doAll || type === 'entities') {
48
+ assertValidationError(!!languageCode, PredictionsValidationErrorCode.NoLanguage);
49
+ const entitiesDetectionParams = {
50
+ Text: text,
51
+ LanguageCode: languageCode,
52
+ };
53
+ entitiesPromise = this.detectEntities(entitiesDetectionParams);
54
+ }
55
+ let sentimentPromise;
56
+ if (doAll || type === 'sentiment') {
57
+ assertValidationError(!!languageCode, PredictionsValidationErrorCode.NoLanguage);
58
+ const sentimentParams = {
59
+ Text: text,
60
+ LanguageCode: languageCode,
61
+ };
62
+ sentimentPromise = this.detectSentiment(sentimentParams);
63
+ }
64
+ let syntaxPromise;
65
+ if (doAll || type === 'syntax') {
66
+ assertValidationError(!!languageCode, PredictionsValidationErrorCode.NoLanguage);
67
+ const syntaxParams = {
68
+ Text: text,
69
+ LanguageCode: languageCode,
70
+ };
71
+ syntaxPromise = this.detectSyntax(syntaxParams);
72
+ }
73
+ let keyPhrasesPromise;
74
+ if (doAll || type === 'keyPhrases') {
75
+ assertValidationError(!!languageCode, PredictionsValidationErrorCode.NoLanguage);
76
+ const keyPhrasesParams = {
77
+ Text: text,
78
+ LanguageCode: languageCode,
79
+ };
80
+ keyPhrasesPromise = this.detectKeyPhrases(keyPhrasesParams);
81
+ }
82
+ const [textEntities, sentiment, syntax, keyPhrases] = await Promise.all([
83
+ entitiesPromise,
84
+ sentimentPromise,
85
+ syntaxPromise,
86
+ keyPhrasesPromise,
87
+ ]);
88
+ return {
89
+ textInterpretation: {
90
+ keyPhrases,
91
+ language: languageCode,
92
+ sentiment,
93
+ syntax,
94
+ textEntities,
95
+ },
96
+ };
97
+ }
98
+ async detectKeyPhrases(params) {
99
+ try {
100
+ const detectKeyPhrasesCommand = new DetectKeyPhrasesCommand(params);
101
+ const data = await this.comprehendClient.send(detectKeyPhrasesCommand);
102
+ const { KeyPhrases = [] } = data || {};
103
+ return KeyPhrases.map(({ Text: text }) => {
104
+ return { text };
105
+ });
106
+ }
107
+ catch (err) {
108
+ if (err.code === 'AccessDeniedException') {
109
+ throw new Error('Not authorized, did you enable Interpret Text on predictions category Amplify CLI? try: ' +
110
+ 'amplify predictions add');
111
+ }
112
+ else {
113
+ throw err;
114
+ }
115
+ }
116
+ }
117
+ async detectSyntax(params) {
118
+ try {
119
+ const detectSyntaxCommand = new DetectSyntaxCommand(params);
120
+ const data = await this.comprehendClient.send(detectSyntaxCommand);
121
+ const { SyntaxTokens = [] } = data || {};
122
+ return this.serializeSyntaxFromComprehend(SyntaxTokens);
123
+ }
124
+ catch (err) {
125
+ if (err.code === 'AccessDeniedException') {
126
+ throw new Error('Not authorized, did you enable Interpret Text on predictions category Amplify CLI? try: ' +
127
+ 'amplify predictions add');
128
+ }
129
+ else {
130
+ throw err;
131
+ }
132
+ }
133
+ }
134
+ serializeSyntaxFromComprehend(tokens) {
135
+ let response = [];
136
+ if (tokens && Array.isArray(tokens)) {
137
+ response = tokens.map(({ Text: text = '', PartOfSpeech: { Tag: syntax = '' } = {} }) => {
138
+ return { text, syntax };
139
+ });
140
+ }
141
+ return response;
142
+ }
143
+ async detectSentiment(params) {
144
+ try {
145
+ const detectSentimentCommand = new DetectSentimentCommand(params);
146
+ const data = await this.comprehendClient.send(detectSentimentCommand);
147
+ const { Sentiment: predominant = '', SentimentScore: { Positive: positive = 0, Negative: negative = 0, Neutral: neutral = 0, Mixed: mixed = 0, } = {}, } = ({} = data);
148
+ return { predominant, positive, negative, neutral, mixed };
149
+ }
150
+ catch (err) {
151
+ if (err.code === 'AccessDeniedException') {
152
+ throw new Error('Not authorized, did you enable Interpret Text on predictions category Amplify CLI? try: ' +
153
+ 'amplify predictions add');
154
+ }
155
+ else {
156
+ throw err;
157
+ }
158
+ }
159
+ }
160
+ async detectEntities(params) {
161
+ try {
162
+ const detectEntitiesCommand = new DetectEntitiesCommand(params);
163
+ const data = await this.comprehendClient.send(detectEntitiesCommand);
164
+ const { Entities = [] } = data || {};
165
+ return this.serializeEntitiesFromComprehend(Entities);
166
+ }
167
+ catch (err) {
168
+ if (err.code === 'AccessDeniedException') {
169
+ throw new Error('Not authorized, did you enable Interpret Text on predictions category Amplify CLI? try: ' +
170
+ 'amplify predictions add');
171
+ }
172
+ else {
173
+ throw err;
174
+ }
175
+ }
176
+ }
177
+ serializeEntitiesFromComprehend(data) {
178
+ let response = [];
179
+ if (data && Array.isArray(data)) {
180
+ response = data.map(({ Type: type, Text: text }) => {
181
+ return { type, text };
182
+ });
183
+ }
184
+ return response;
185
+ }
186
+ async detectLanguage(params) {
187
+ try {
188
+ const detectDominantLanguageCommand = new DetectDominantLanguageCommand(params);
189
+ const data = await this.comprehendClient.send(detectDominantLanguageCommand);
190
+ const { Languages: [{ LanguageCode }] = [{}] } = ({} = data || {});
191
+ assertValidationError(!!LanguageCode, PredictionsValidationErrorCode.NoLanguage);
192
+ return LanguageCode;
193
+ }
194
+ catch (err) {
195
+ if (err.code === 'AccessDeniedException') {
196
+ throw new Error('Not authorized, did you enable Interpret Text on predictions category Amplify CLI? try: ' +
197
+ 'amplify predictions add');
198
+ }
199
+ else {
200
+ throw err;
201
+ }
202
+ }
203
+ }
204
+ }
@@ -0,0 +1,16 @@
1
+ import { IdentifyTextOutput } from '../types';
2
+ import { BlockList, TextDetectionList } from '../types/AWSTypes';
3
+ /**
4
+ * Organizes blocks from Rekognition API to each of the categories and and structures
5
+ * their data accordingly.
6
+ * @param {BlockList} source - Array containing blocks returned from Textract API.
7
+ * @return {IdentifyTextOutput} - Object that categorizes each block and its information.
8
+ */
9
+ export declare function categorizeRekognitionBlocks(blocks: TextDetectionList): IdentifyTextOutput;
10
+ /**
11
+ * Organizes blocks from Textract API to each of the categories and and structures
12
+ * their data accordingly.
13
+ * @param {BlockList} source - Array containing blocks returned from Textract API.
14
+ * @return {IdentifyTextOutput} - Object that categorizes each block and its information.
15
+ */
16
+ export declare function categorizeTextractBlocks(blocks: BlockList): IdentifyTextOutput;