@azure-rest/health-insights-radiologyinsights 1.0.0-beta.1 → 1.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.
- package/README.md +558 -50
- package/dist/index.js +73 -11
- package/dist/index.js.map +1 -1
- package/dist-esm/src/azureHealthInsightsClient.js +11 -9
- package/dist-esm/src/azureHealthInsightsClient.js.map +1 -1
- package/dist-esm/src/clientDefinitions.js.map +1 -1
- package/dist-esm/src/index.js +3 -2
- package/dist-esm/src/index.js.map +1 -1
- package/dist-esm/src/isUnexpected.js +2 -2
- package/dist-esm/src/isUnexpected.js.map +1 -1
- package/dist-esm/src/models.js +19 -1
- package/dist-esm/src/models.js.map +1 -1
- package/dist-esm/src/outputModels.js +20 -1
- package/dist-esm/src/outputModels.js.map +1 -1
- package/dist-esm/src/parameters.js.map +1 -1
- package/dist-esm/src/pollingHelper.js.map +1 -1
- package/dist-esm/src/responses.js.map +1 -1
- package/dist-esm/src/serializeHelper.js +14 -0
- package/dist-esm/src/serializeHelper.js.map +1 -0
- package/package.json +7 -8
- package/review/health-insights-radiologyinsights.api.md +396 -131
package/README.md
CHANGED
|
@@ -7,14 +7,7 @@
|
|
|
7
7
|
**Please rely heavily on our [REST client docs](https://github.com/Azure/azure-sdk-for-js/blob/main/documentation/rest-clients.md) to use this library**
|
|
8
8
|
|
|
9
9
|
Key links:
|
|
10
|
-
|
|
11
|
-
Key links:
|
|
12
|
-
|
|
13
|
-
- [Source code]
|
|
14
|
-
- [Package (NPM)]
|
|
15
|
-
- [API reference documentation]
|
|
16
|
-
- [Product Information](https://docs.microsoft.com/rest/api/maps/route)
|
|
17
|
-
- [Samples]
|
|
10
|
+
[Source code] | [Package (NPM)] | [API reference documentation] | [Product Information] | [Samples]
|
|
18
11
|
|
|
19
12
|
## Getting started
|
|
20
13
|
|
|
@@ -39,10 +32,6 @@ npm install @azure-rest/health-insights-radiologyinsights
|
|
|
39
32
|
|
|
40
33
|
### Create and authenticate a `RadiologyInsightsClient`
|
|
41
34
|
|
|
42
|
-
|SDK version|Supported API version of service |
|
|
43
|
-
|-------------|---------------|
|
|
44
|
-
|1.0.0-beta.1 | 2024-01-19-preview|
|
|
45
|
-
|
|
46
35
|
To use an [Azure Active Directory (AAD) token credential][token_credential],
|
|
47
36
|
provide an instance of the desired credential type obtained from the [Azure Identity library][azure_identity].
|
|
48
37
|
|
|
@@ -50,35 +39,45 @@ To authenticate with AAD, you must first `npm` install [`@azure/identity`][ident
|
|
|
50
39
|
|
|
51
40
|
After setup, you can choose which type of [credential][credential] from `@azure/identity` to use.
|
|
52
41
|
As an example, [DefaultAzureCredential][defaultazurecredential]
|
|
53
|
-
can be used to authenticate the client.
|
|
54
|
-
|
|
55
|
-
Set the values of the client ID, tenant ID, and client secret of the AAD application as environment variables:
|
|
56
|
-
AZURE_CLIENT_ID, AZURE_TENANT_ID, AZURE_CLIENT_SECRET
|
|
42
|
+
can be used to authenticate the client. See more info on defaultAzureCredentials [default_information].
|
|
43
|
+
Managed Identities can also be used to authenticate through DefaultAzureCredential [managed_identity].
|
|
57
44
|
|
|
58
45
|
## Examples
|
|
59
46
|
|
|
60
47
|
### Create a RadiologyInsights asynchronous client
|
|
61
48
|
|
|
62
49
|
```typescript
|
|
63
|
-
const apiKey = process.env["HEALTH_INSIGHTS_API_KEY"] || "";
|
|
64
50
|
const endpoint = process.env["HEALTH_INSIGHTS_ENDPOINT"] || "";
|
|
65
|
-
const credential = new
|
|
51
|
+
const credential = new DefaultAzureCredential();
|
|
66
52
|
const client = RadiologyInsightsRestClient(endpoint, credential);
|
|
67
53
|
```
|
|
68
54
|
|
|
69
|
-
|
|
55
|
+
|
|
56
|
+
### Build a request, send it to the client and print out the description of a Critical Result Inference
|
|
70
57
|
|
|
71
58
|
```typescript
|
|
72
59
|
|
|
73
60
|
export async function main() {
|
|
74
|
-
const credential = new
|
|
61
|
+
const credential = new DefaultAzureCredential();
|
|
75
62
|
const client = AzureHealthInsightsClient(endpoint, credential);
|
|
63
|
+
|
|
64
|
+
// if you want to use DefaultAzureCredential in you test, you can use the createTestCredential to do the correct switches between node and browser tests
|
|
65
|
+
import { createTestCredential } from "@azure-tools/test-credential";
|
|
66
|
+
|
|
67
|
+
export async function createTestClient(recorder: Recorder): Promise<AzureHealthInsightsClient> {
|
|
68
|
+
const endpoint = assertEnvironmentVariable("HEALTH_INSIGHTS_ENDPOINT");
|
|
69
|
+
const credential = createTestCredential();
|
|
70
|
+
return AHIClient(endpoint, credential, recorder.configureClientOptions({}));
|
|
71
|
+
}
|
|
76
72
|
|
|
77
73
|
// Create request body
|
|
78
74
|
const radiologyInsightsParameter = createRequestBody();
|
|
79
75
|
|
|
80
76
|
// Initiate radiology insights job and retrieve results
|
|
81
|
-
|
|
77
|
+
// The jobID can be adapted by preference of the client, there are restrictions in size and it cannot contain spaces
|
|
78
|
+
const dateString = Date.now();
|
|
79
|
+
const jobID = "jobId-" + dateString;
|
|
80
|
+
const initialResponse = await client.path("/radiology-insights/jobs/{id}", jobID).put(radiologyInsightsParameter);
|
|
82
81
|
if (isUnexpected(initialResponse)) {
|
|
83
82
|
throw initialResponse;
|
|
84
83
|
}
|
|
@@ -118,9 +117,9 @@ function createRequestBody(): CreateJobParameters {
|
|
|
118
117
|
};
|
|
119
118
|
|
|
120
119
|
const authorData = {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
120
|
+
id: "authorid1",
|
|
121
|
+
fullName: "authorname1",
|
|
122
|
+
};
|
|
124
123
|
|
|
125
124
|
const orderedProceduresData = {
|
|
126
125
|
code: code,
|
|
@@ -134,46 +133,48 @@ function createRequestBody(): CreateJobParameters {
|
|
|
134
133
|
|
|
135
134
|
const content = {
|
|
136
135
|
sourceType: "inline",
|
|
137
|
-
value:
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
136
|
+
value: `CLINICAL HISTORY:
|
|
137
|
+
20-year-old female presenting with abdominal pain. Surgical history significant for appendectomy.
|
|
138
|
+
|
|
139
|
+
COMPARISON:
|
|
140
|
+
Right upper quadrant sonographic performed 1 day prior.
|
|
141
|
+
|
|
142
|
+
TECHNIQUE:
|
|
143
|
+
Transabdominal grayscale pelvic sonography with duplex color Doppler
|
|
144
|
+
and spectral waveform analysis of the ovaries.
|
|
145
|
+
|
|
146
|
+
FINDINGS:
|
|
147
|
+
The uterus is unremarkable given the transabdominal technique with
|
|
148
|
+
endometrial echo complex within physiologic normal limits. The
|
|
149
|
+
ovaries are symmetric in size, measuring 2.5 x 1.2 x 3.0 cm and the
|
|
150
|
+
left measuring 2.8 x 1.5 x 1.9 cm.
|
|
151
|
+
|
|
152
|
+
On duplex imaging, Doppler signal is symmetric.
|
|
153
|
+
|
|
154
|
+
IMPRESSION:
|
|
155
|
+
1. Normal pelvic sonography. Findings of testicular torsion.
|
|
156
|
+
A new US pelvis within the next 6 months is recommended.
|
|
157
|
+
|
|
158
|
+
These results have been discussed with Dr. Jones at 3 PM on November 5 2020.`,
|
|
158
159
|
};
|
|
159
160
|
|
|
160
161
|
const patientDocumentData = {
|
|
161
162
|
type: "note",
|
|
162
|
-
clinicalType:
|
|
163
|
+
clinicalType: ClinicalDocumentTypeEnum.RadiologyReport,
|
|
163
164
|
id: "docid1",
|
|
164
165
|
language: "en",
|
|
165
166
|
authors: [authorData],
|
|
166
167
|
specialtyType: "radiology",
|
|
167
168
|
administrativeMetadata: administrativeMetadata,
|
|
168
169
|
content: content,
|
|
169
|
-
|
|
170
|
+
createdAt: new Date("2021-05-31T16:00:00.000Z"),
|
|
170
171
|
orderedProceduresAsCsv: "US PELVIS COMPLETE"
|
|
171
172
|
};
|
|
172
173
|
|
|
173
174
|
|
|
174
175
|
const patientData = {
|
|
175
176
|
id: "Samantha Jones",
|
|
176
|
-
|
|
177
|
+
details: patientInfo,
|
|
177
178
|
encounters: [encounterData],
|
|
178
179
|
patientDocuments: [patientDocumentData]
|
|
179
180
|
};
|
|
@@ -225,7 +226,7 @@ function createRequestBody(): CreateJobParameters {
|
|
|
225
226
|
|
|
226
227
|
}
|
|
227
228
|
|
|
228
|
-
function printResults(radiologyInsightsResult:
|
|
229
|
+
function printResults(radiologyInsightsResult: RadiologyInsightsJobOutput): void {
|
|
229
230
|
if (radiologyInsightsResult.status === "succeeded") {
|
|
230
231
|
const results = radiologyInsightsResult.result;
|
|
231
232
|
if (results !== undefined) {
|
|
@@ -249,6 +250,507 @@ function printResults(radiologyInsightsResult: RadiologyInsightsResultOutput): v
|
|
|
249
250
|
}
|
|
250
251
|
}
|
|
251
252
|
```
|
|
253
|
+
### Print out the Age Mismatch Inference evidences
|
|
254
|
+
```typescript
|
|
255
|
+
function printResults(radiologyInsightsResult: RadiologyInsightsJobOutput, content: string): void {
|
|
256
|
+
if (radiologyInsightsResult.status === "succeeded") {
|
|
257
|
+
const results = radiologyInsightsResult.result;
|
|
258
|
+
if (results !== undefined) {
|
|
259
|
+
results.patientResults.forEach((patientResult: any) => {
|
|
260
|
+
if (patientResult.inferences) {
|
|
261
|
+
patientResult.inferences.forEach((inference: any) => {
|
|
262
|
+
if (inference.kind === "ageMismatch") {
|
|
263
|
+
console.log("Age Mismatch Inference found: ");
|
|
264
|
+
const evidence = findAgeEvidence(inference.extension, content);
|
|
265
|
+
console.log(" Evidence: " + evidence);
|
|
266
|
+
}
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
const error = radiologyInsightsResult.error;
|
|
273
|
+
if (error) {
|
|
274
|
+
console.log(error.code, ":", error.message);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function findAgeEvidence(extensions: any, content: string) {
|
|
279
|
+
let offset = -1;
|
|
280
|
+
let length = -1;
|
|
281
|
+
let piece = "";
|
|
282
|
+
let evidence = "";
|
|
283
|
+
// for loop needed for traversing from top to bottom of the array
|
|
284
|
+
for (const first of extensions) {
|
|
285
|
+
for (const ext of first.extension) {
|
|
286
|
+
if (ext.url === "offset") {
|
|
287
|
+
offset = ext.valueInteger;
|
|
288
|
+
} else if (ext.url === "length") {
|
|
289
|
+
length = ext.valueInteger;
|
|
290
|
+
}
|
|
291
|
+
if (offset > 0 && length > 0) {
|
|
292
|
+
piece = content.substring(offset, offset + length);
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
evidence += `${piece} `;
|
|
296
|
+
}
|
|
297
|
+
return evidence;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
}
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Print out the Complete Order Discrepancy Inference ordertype and its missing Body Parts and missing Body Part Measurements
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
function printResults(radiologyInsightsResult: RadiologyInsightsJobOutput): void {
|
|
307
|
+
if (radiologyInsightsResult.status === "succeeded") {
|
|
308
|
+
const results = radiologyInsightsResult.result;
|
|
309
|
+
if (results !== undefined) {
|
|
310
|
+
results.patientResults.forEach((patientResult: any) => {
|
|
311
|
+
if (patientResult.inferences) {
|
|
312
|
+
patientResult.inferences.forEach((inference: any) => {
|
|
313
|
+
if (inference.kind === "completeOrderDiscrepancy") {
|
|
314
|
+
console.log("Complete Order Discrepancy Inference found: ");
|
|
315
|
+
if ("orderType" in inference) {
|
|
316
|
+
console.log(" Ordertype: ");
|
|
317
|
+
displayCodes({ codeableConcept: inference.orderType });
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
inference.missingBodyParts?.forEach((bodyparts: any) => {
|
|
321
|
+
console.log(" Missing Body Parts: ");
|
|
322
|
+
displayCodes({ codeableConcept: bodyparts });
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
inference.missingBodyPartMeasurements?.forEach((bodymeasure: any) => {
|
|
326
|
+
console.log(" Missing Body Part Measurements: ");
|
|
327
|
+
displayCodes({ codeableConcept: bodymeasure });
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
} else {
|
|
335
|
+
const error = radiologyInsightsResult.error;
|
|
336
|
+
if (error) {
|
|
337
|
+
console.log(error.code, ":", error.message);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function displayCodes({ codeableConcept }: { codeableConcept: any; }): void {
|
|
342
|
+
codeableConcept.coding?.forEach((coding: any) => {
|
|
343
|
+
if ("code" in coding) {
|
|
344
|
+
console.log(" Coding: " + coding.code + ", " + coding.display + " (" + coding.system + ")");
|
|
345
|
+
}
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
}
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
### Print out the Finding Inference code, interpretation, Component codes and the section info
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
function printResults(radiologyInsightsResult: RadiologyInsightsJobOutput): void {
|
|
356
|
+
if (radiologyInsightsResult.status === "succeeded") {
|
|
357
|
+
const results = radiologyInsightsResult.result;
|
|
358
|
+
if (results !== undefined) {
|
|
359
|
+
results.patientResults.forEach((patientResult: { inferences: any[]; }) => {
|
|
360
|
+
if (patientResult.inferences) {
|
|
361
|
+
patientResult.inferences.forEach((inference) => {
|
|
362
|
+
if (inference.kind === "finding") {
|
|
363
|
+
console.log("Finding Inference found: ");
|
|
364
|
+
|
|
365
|
+
let find = inference.finding;
|
|
366
|
+
if ("code" in find) {
|
|
367
|
+
let fcode = find.code;
|
|
368
|
+
console.log(" Code: ");
|
|
369
|
+
displayCodes(fcode);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
find.interpretation?.forEach((inter: any) => {
|
|
373
|
+
console.log(" Interpretation: ");
|
|
374
|
+
displayCodes(inter);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
inference.finding.component?.forEach((comp: { code: any; valueCodeableConcept: any }) => {
|
|
378
|
+
console.log(" Component code: ");
|
|
379
|
+
displayCodes(comp.code);
|
|
380
|
+
if ("valueCodeableConcept" in comp) {
|
|
381
|
+
console.log(" Value component codeable concept: ");
|
|
382
|
+
displayCodes(comp.valueCodeableConcept);
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
if ("extension" in inference) {
|
|
387
|
+
displaySectionInfo(inference);
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
} else {
|
|
396
|
+
const error = radiologyInsightsResult.error;
|
|
397
|
+
if (error) {
|
|
398
|
+
console.log(error.code, ":", error.message);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
function displayCodes(codeableConcept: any): void {
|
|
403
|
+
codeableConcept.coding?.forEach((coding: any) => {
|
|
404
|
+
if ("code" in coding) {
|
|
405
|
+
console.log(" Coding: " + coding.code + ", " + coding.display + " (" + coding.system + ")");
|
|
406
|
+
}
|
|
407
|
+
});
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
function displaySectionInfo(inference: { extension: any[]; }) {
|
|
411
|
+
inference.extension?.forEach((ext: any) => {
|
|
412
|
+
if ("url" in ext && ext.url === "section") {
|
|
413
|
+
console.log(" Section:");
|
|
414
|
+
ext.extension?.forEach((subextension: { url: string; valueString: string; }) => {
|
|
415
|
+
if ("url" in subextension && "valueString" in subextension) {
|
|
416
|
+
console.log(" " + subextension.url + ": " + subextension.valueString);
|
|
417
|
+
}
|
|
418
|
+
});
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
}
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
### Print out the Follow Up Communication Inference date and recipient
|
|
427
|
+
|
|
428
|
+
```typescript
|
|
429
|
+
function printResults(radiologyInsightsResult: RadiologyInsightsJobOutput): void {
|
|
430
|
+
if (radiologyInsightsResult.status === "succeeded") {
|
|
431
|
+
const results = radiologyInsightsResult.result;
|
|
432
|
+
if (results !== undefined) {
|
|
433
|
+
results.patientResults.forEach((patientResult: any) => {
|
|
434
|
+
patientResult.inferences.forEach((inference: { kind: string; communicatedAt: any[]; recipient: any[]; wasAcknowledged: string; }) => {
|
|
435
|
+
if (inference.kind === "followupCommunication") {
|
|
436
|
+
console.log("Followup Communication Inference found");
|
|
437
|
+
if ("communicatedAt" in inference) {
|
|
438
|
+
console.log("Communicated at: " + inference.communicatedAt.join(" "));
|
|
439
|
+
}
|
|
440
|
+
if ("recipient" in inference) {
|
|
441
|
+
console.log("Recipient: " + inference.recipient.join(" "));
|
|
442
|
+
}
|
|
443
|
+
console.log(" Aknowledged: " + inference.wasAcknowledged);
|
|
444
|
+
}
|
|
445
|
+
});
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
} else {
|
|
449
|
+
const error = radiologyInsightsResult.error;
|
|
450
|
+
if (error) {
|
|
451
|
+
console.log(error.code, ":", error.message);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
### Print out the Follow Up Recommendation Inference booleans, Generic Procedure code, description and Imaging Procedure codes
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
function printResults(radiologyInsightsResult: RadiologyInsightsJobOutput): void {
|
|
462
|
+
if (radiologyInsightsResult.status === "succeeded") {
|
|
463
|
+
const results = radiologyInsightsResult.result;
|
|
464
|
+
if (results !== undefined) {
|
|
465
|
+
results.patientResults.forEach((patientResult: any) => {
|
|
466
|
+
patientResult.inferences.forEach((inference: { kind: string; isConditional: any; isGuideline: any; isHedging: any; isOption: any; recommendedProcedure: any; }) => {
|
|
467
|
+
if (inference.kind === "followupRecommendation") {
|
|
468
|
+
console.log("Follow Up Recommendation Inference found");
|
|
469
|
+
console.log(" Is conditional: ", inference.isConditional);
|
|
470
|
+
console.log(" Is guidline: ", inference.isGuideline);
|
|
471
|
+
console.log(" Is hedging: ", inference.isHedging);
|
|
472
|
+
console.log(" Is option: ", inference.isOption);
|
|
473
|
+
|
|
474
|
+
var procedure = inference.recommendedProcedure;
|
|
475
|
+
if ("kind" in procedure && procedure.kind === "genericProcedureRecommendation") {
|
|
476
|
+
if ("code" in procedure) {
|
|
477
|
+
console.log(" Recommended Generic Procedure: ", procedure.code);
|
|
478
|
+
}
|
|
479
|
+
if ("description" in procedure) {
|
|
480
|
+
console.log(" Description: ", procedure.description);
|
|
481
|
+
}
|
|
482
|
+
} else if ("kind" in procedure && procedure.kind === "imagingProcedureRecommendation") {
|
|
483
|
+
procedure.procedureCodes?.forEach((procedureCode: any) => {
|
|
484
|
+
console.log(" Recommended Procedure Codes: ");
|
|
485
|
+
displayCodes(procedureCode);
|
|
486
|
+
});
|
|
487
|
+
|
|
488
|
+
if ("imagingProcedures" in procedure) {
|
|
489
|
+
procedure.imagingProcedures?.forEach((imagingProcedure: any) => {
|
|
490
|
+
console.log(" Recommended Imaging Procedure Codes: ");
|
|
491
|
+
displayImaging(imagingProcedure);
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
} else {
|
|
500
|
+
const error = radiologyInsightsResult.error;
|
|
501
|
+
if (error) {
|
|
502
|
+
console.log(error.code, ":", error.message);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function displayCodes(codeableConcept: any): void {
|
|
507
|
+
codeableConcept.coding?.forEach((coding: any) => {
|
|
508
|
+
if ("code" in coding) {
|
|
509
|
+
console.log(" Coding: " + coding.code + ", " + coding.display + " (" + coding.system + ")");
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function displayImaging(images: { modality: { coding: any[]; }; anatomy: { coding: any[]; }; laterality: { coding: any[]; }; contrast: { code: { coding: any[]; }; }; view: { code: { coding: any[]; }; }; }) {
|
|
515
|
+
console.log(" Modality Codes: ");
|
|
516
|
+
displayCodes(images.modality);
|
|
517
|
+
console.log(" Anatomy Codes: ");
|
|
518
|
+
displayCodes(images.anatomy);
|
|
519
|
+
if ("laterality" in images) {
|
|
520
|
+
console.log(" Laterality Codes: ");
|
|
521
|
+
displayCodes(images.laterality);
|
|
522
|
+
}
|
|
523
|
+
if ("contrast" in images) {
|
|
524
|
+
console.log(" Contrast Codes: ");
|
|
525
|
+
displayCodes(images.contrast.code);
|
|
526
|
+
}
|
|
527
|
+
if ("view" in images) {
|
|
528
|
+
console.log(" View Codes: ");
|
|
529
|
+
displayCodes(images.view.code);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
### Print out the Laterality Discrepancy Inference code
|
|
537
|
+
|
|
538
|
+
```typescript
|
|
539
|
+
function printResults(radiologyInsightsResult: RadiologyInsightsJobOutput): void {
|
|
540
|
+
if (radiologyInsightsResult.status === "succeeded") {
|
|
541
|
+
const results = radiologyInsightsResult.result;
|
|
542
|
+
if (results !== undefined) {
|
|
543
|
+
results.patientResults.forEach((patientResult: any) => {
|
|
544
|
+
patientResult.inferences.forEach((inference: { kind: string; lateralityIndication: any }) => {
|
|
545
|
+
if (inference.kind === "lateralityDiscrepancy") {
|
|
546
|
+
console.log("Laterality Discrepancy Inference found: ");
|
|
547
|
+
displayCodes(inference.lateralityIndication);
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
} else {
|
|
553
|
+
const error = radiologyInsightsResult.error;
|
|
554
|
+
if (error) {
|
|
555
|
+
console.log(error.code, ":", error.message);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
function displayCodes(codeableConcept: any): void {
|
|
560
|
+
codeableConcept.coding?.forEach((coding: any) => {
|
|
561
|
+
if ("code" in coding) {
|
|
562
|
+
console.log(" Coding: " + coding.code + ", " + coding.display + " (" + coding.system + "), type: " + coding.type);
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
}
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
### Print out the Limited Order Discrepancy Inference ordertype with present Body Parts and present Body Part Measurements
|
|
571
|
+
|
|
572
|
+
```typescript
|
|
573
|
+
function printResults(radiologyInsightsResult: RadiologyInsightsJobOutput): void {
|
|
574
|
+
if (radiologyInsightsResult.status === "succeeded") {
|
|
575
|
+
const results = radiologyInsightsResult.result;
|
|
576
|
+
if (results !== undefined) {
|
|
577
|
+
results.patientResults.forEach((patientResult: { inferences: any[]; }) => {
|
|
578
|
+
if (patientResult.inferences) {
|
|
579
|
+
patientResult.inferences.forEach((inference) => {
|
|
580
|
+
if (inference.kind === "limitedOrderDiscrepancy") {
|
|
581
|
+
console.log("Limited Order Discrepancy Inference found: ");
|
|
582
|
+
if ("orderType" in inference) {
|
|
583
|
+
console.log(" Ordertype: ");
|
|
584
|
+
displayCodes(inference.orderType);
|
|
585
|
+
};
|
|
586
|
+
|
|
587
|
+
inference.presentBodyParts?.forEach((bodyparts: any) => {
|
|
588
|
+
console.log(" Present Body Parts: ");
|
|
589
|
+
displayCodes(bodyparts);
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
inference.presentBodyPartMeasurements?.forEach((bodymeasure: any) => {
|
|
593
|
+
console.log(" Present Body Part Measurements: ");
|
|
594
|
+
displayCodes(bodymeasure);
|
|
595
|
+
});
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
} else {
|
|
602
|
+
const error = radiologyInsightsResult.error;
|
|
603
|
+
if (error) {
|
|
604
|
+
console.log(error.code, ":", error.message);
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
function displayCodes(codeableConcept: any): void {
|
|
609
|
+
codeableConcept.coding?.forEach((coding: any) => {
|
|
610
|
+
if ("code" in coding) {
|
|
611
|
+
console.log(" Coding: " + coding.code + ", " + coding.display + " (" + coding.system + ")");
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
}
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
### Print out the Radiology Procedure Inference codes, Imaging Procedure codes and Order Procedure Codes and its description
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
function printResults(radiologyInsightsResult: RadiologyInsightsJobOutput): void {
|
|
623
|
+
if (radiologyInsightsResult.status === "succeeded") {
|
|
624
|
+
const results = radiologyInsightsResult.result;
|
|
625
|
+
if (results !== undefined) {
|
|
626
|
+
results.patientResults.forEach((patientResult: { inferences: any[]; }) => {
|
|
627
|
+
if (patientResult.inferences) {
|
|
628
|
+
patientResult.inferences.forEach((inference) => {
|
|
629
|
+
if (inference.kind === "radiologyProcedure") {
|
|
630
|
+
console.log("Radiology Procedure Inference found");
|
|
631
|
+
inference.procedureCodes?.forEach((procedureCode: any) => {
|
|
632
|
+
console.log(" Procedure Codes: ");
|
|
633
|
+
displayCodes(procedureCode);
|
|
634
|
+
});
|
|
635
|
+
|
|
636
|
+
if ("imagingProcedures" in inference) {
|
|
637
|
+
inference.imagingProcedures?.forEach((imagingProcedure: any) => {
|
|
638
|
+
console.log(" Imaging Procedure Codes: ");
|
|
639
|
+
displayImaging(imagingProcedure);
|
|
640
|
+
});
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
if ("orderedProcedure" in inference) {
|
|
644
|
+
console.log(" Ordered procedures: ");
|
|
645
|
+
if ("code" in inference.orderedProcedure) {
|
|
646
|
+
displayCodes(inference.orderedProcedure.code);
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
if ("description" in inference.orderedProcedure) {
|
|
651
|
+
console.log(" Description: " + inference.orderedProcedure.description);
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
});
|
|
657
|
+
}
|
|
658
|
+
} else {
|
|
659
|
+
const error = radiologyInsightsResult.error;
|
|
660
|
+
if (error) {
|
|
661
|
+
console.log(error.code, ":", error.message);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
function displayCodes(codeableConcept: any): void {
|
|
666
|
+
codeableConcept.coding?.forEach((coding: any) => {
|
|
667
|
+
if ("code" in coding) {
|
|
668
|
+
console.log(" Coding: " + coding.code + ", " + coding.display + " (" + coding.system + ")");
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
function displayImaging(images: any): void {
|
|
674
|
+
console.log(" Modality Codes: ");
|
|
675
|
+
displayCodes(images.modality);
|
|
676
|
+
console.log(" Anatomy Codes: ");
|
|
677
|
+
displayCodes(images.anatomy);
|
|
678
|
+
if ("laterality" in images) {
|
|
679
|
+
console.log(" Laterality Codes: ");
|
|
680
|
+
displayCodes(images.laterality);
|
|
681
|
+
}
|
|
682
|
+
if ("contrast" in images) {
|
|
683
|
+
console.log(" Contrast Codes: ");
|
|
684
|
+
displayCodes(images.contrast.code);
|
|
685
|
+
}
|
|
686
|
+
if ("view" in images) {
|
|
687
|
+
console.log(" View Codes: ");
|
|
688
|
+
displayCodes(images.view.code);
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
}
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
### Print out the Sex Mismatch Inference code
|
|
696
|
+
|
|
697
|
+
```typescript
|
|
698
|
+
function printResults(radiologyInsightsResult: RadiologyInsightsJobOutput): void {
|
|
699
|
+
if (radiologyInsightsResult.status === "succeeded") {
|
|
700
|
+
const results = radiologyInsightsResult.result;
|
|
701
|
+
if (results !== undefined) {
|
|
702
|
+
results.patientResults.forEach((patientResult: { inferences: any[]; }) => {
|
|
703
|
+
if (patientResult.inferences) {
|
|
704
|
+
patientResult.inferences.forEach((inference) => {
|
|
705
|
+
if (inference.kind === "sexMismatch") {
|
|
706
|
+
console.log("Sex Mismatch Inference found: ");
|
|
707
|
+
if ("sexIndication" in inference) {
|
|
708
|
+
displayCodes(inference.sexIndication)
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
});
|
|
714
|
+
}
|
|
715
|
+
} else {
|
|
716
|
+
const error = radiologyInsightsResult.error;
|
|
717
|
+
if (error) {
|
|
718
|
+
console.log(error.code, ":", error.message);
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
function displayCodes(codeableConcept: any): void {
|
|
723
|
+
codeableConcept.coding?.forEach((coding: any) => {
|
|
724
|
+
if ("code" in coding) {
|
|
725
|
+
console.log(" Coding: " + coding.code + ", " + coding.display + " (" + coding.system + ")");
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
}
|
|
731
|
+
|
|
732
|
+
```
|
|
733
|
+
## Using a Managed Identity require changes in adding the clientID of your managed identity as a const, adding it to you DefaultAzureCredential and add the Authorization Header
|
|
734
|
+
|
|
735
|
+
```typescript
|
|
736
|
+
const clientID = process.env["MANAGED_IDENTITY_CLIENT_ID"] || "";
|
|
737
|
+
...
|
|
738
|
+
|
|
739
|
+
//Create Managed Identity Credential
|
|
740
|
+
const credential = new DefaultAzureCredential(
|
|
741
|
+
clientID ? { managedIdentityClientId: clientID } : undefined,
|
|
742
|
+
);
|
|
743
|
+
const tokenResponse = await credential.getToken('https://cognitiveservices.azure.com/.default');
|
|
744
|
+
logger.info(null, `Got token for Cognitive Services ${tokenResponse?.token}`);
|
|
745
|
+
|
|
746
|
+
const initialResponse = await client.path("/radiology-insights/jobs/{id}", jobID).put(radiologyInsightsParameter, {
|
|
747
|
+
headers: {
|
|
748
|
+
'Authorization': `Bearer ${tokenResponse?.token}`,
|
|
749
|
+
'Content-Type': 'application/json'
|
|
750
|
+
},
|
|
751
|
+
});
|
|
752
|
+
|
|
753
|
+
```
|
|
252
754
|
|
|
253
755
|
## Troubleshooting
|
|
254
756
|
|
|
@@ -267,9 +769,15 @@ For more detailed instructions on how to enable logs, you can look at the [@azur
|
|
|
267
769
|
<!-- LINKS -->
|
|
268
770
|
[health_insights]: https://learn.microsoft.com/azure/azure-health-insights/overview
|
|
269
771
|
[radiology_insights_docs]: https://learn.microsoft.com/azure/azure-health-insights/radiology-insights/
|
|
270
|
-
|
|
772
|
+
[Source code]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/healthinsights/health-insights-radiologyinsights-rest
|
|
773
|
+
[Package (NPM)]: https://www.npmjs.com/package/@azure-rest/health-insights-radiologyinsights
|
|
774
|
+
[API reference documentation]: https://learn.microsoft.com/rest/api/cognitiveservices/healthinsights/operation-groups?view=rest-cognitiveservices-healthinsights-2024-04-01
|
|
775
|
+
[Product Information]: https://learn.microsoft.com/azure/azure-health-insights/radiology-insights/overview
|
|
776
|
+
[Samples]:https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/healthinsights/health-insights-radiologyinsights-rest/samples/v1
|
|
271
777
|
[azure_identity]: https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/identity/identity
|
|
272
778
|
[identity]: https://www.npmjs.com/package/@azure/identity
|
|
273
779
|
[token_credential]: https://github.com/Azure/azure-sdk-for-js/blob/main/sdk/identity/identity/samples/AzureIdentityExamples.md#authenticating-with-a-pre-fetched-access-token
|
|
274
780
|
[defaultazurecredential]: https://github.com/Azure/azure-sdk-for-js/tree/master/sdk/identity/identity#defaultazurecredential
|
|
781
|
+
[default_information]: https://learn.microsoft.com/javascript/api/%40azure/identity/defaultazurecredential?view=azure-node-latest
|
|
782
|
+
[managed_identity]: https://learn.microsoft.com/javascript/api/%40azure/identity/managedidentitycredential?view=azure-node-latest
|
|
275
783
|
[credential]: https://github.com/Azure/azure-sdk-for-js/tree/main/sdk/identity/identity#credentials
|