-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathapp.js
162 lines (138 loc) · 6.11 KB
/
app.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
/**
* Objective: Prototype local app to access and request ICD API for data on flu symptoms
* GOAL #1: Access ICD API
* GOAL #2: Send request with symptoms and receive data
* API Call references
* Broader results list - /icd/release/11/{releasId}/{linearizationName}/search
* Narrowed down result - /icd/release/11/2024-01/mms/autocode?searchText=sore%20throat&matchThreshold=0.75
* GOAL #3: Deduce data and log text in user-readable format
* Use 'foundationURI' from Narrowed down result
* API call - /icd/release/11/2024-01/mms/lookup?foundationUri=http%3A%2F%2Fid.who.int%2Ficd%2Fentity%2F633724732
* response includes 'browserUrl', 'title', 'definition',
* other possible conditions list - 'exclusion', 'indexTerm'
**/
// imports
const middleware = require('./middleware')
// Goal #1 : Setup ICD API access
// ICD API authentication to OAUTH 2.0 Token Endpoint (token from API for access)
const tokenEndpoint = 'https://icdaccessmanagement.who.int/connect/token'
const clientId = process.env.CLIENT_ID
const clientSecret = process.env.CLIENT_SECRET
console.log('Credentials loaded')
// collect payload data as 'payload'
const payload = {
'client_id': clientId,
'client_secret': clientSecret,
'scope': 'icdapi_access',
'grant_type': 'client_credentials'
}
// convert payload to URL-encoded format
const requestBody = Object.keys(payload)
.map(key => encodeURIComponent(key) + '=' + encodeURIComponent(payload[key]))
.join('&')
console.log('Payload URL-encoded')
// setup request options for fetching token
const tokenOptions = {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
},
body: requestBody
}
console.log('Options set');
// Goal #2: Send request with symptoms and receive data
// Foundation Model : https://icd.who.int/browse/2024-01/foundation/en#448895267
// access middleware to authenticate access and setup scheduled token update
const getTokenAndData = async() => {
const token = await middleware.authenticateApiAccess(tokenEndpoint, tokenOptions)
console.log('Fetching token...');
console.log('Token: ', token)
const requestOptions = {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
'API-Version': 'v2',
'Accept-Language': 'en',
'Accept': 'application/json'
}
}
// search API for symptom
const searchUrl = 'https://id.who.int/icd/release/11/2024-01/mms/autocode'
const symptom = 'sore throat'
// Broader results list - /icd/release/11/{releaseId}/{linearizationName}/search
// const searchParams = {
// q: symptom,
// useFlexiSearch: 'false',
// flatResults: 'true',
// subtreeFilterUsesFoundationDescendants: 'false',
// includeKeywordResult: 'true',
// medicalCodingMode: 'true',
// // valid values: "Title", "Synonym", "NarrowerTerm", "FullySpecifiedName", "Definition", "Exclusion"
// // More than one property could be used with "," as the separator.
// propertiesToBeSearched: 'IndexTerm',
// highlightingEnabled: 'true'
// }
// Narrowed down result - /icd/release/11/2024-01/mms/autocode
const searchParams = {
searchText: symptom,
matchThreshold: 0.75
}
// construct query string for URI
const searchString = new URLSearchParams(searchParams)
// setup search request to endpoint
const searchEndpoint = `${searchUrl}?${searchString}`
const searchResponse = await fetch(searchEndpoint, requestOptions)
console.log(`\nStatus ${requestOptions.method} ${searchUrl} :\n${searchResponse.status}`)
// GOAL #3: Extract data and display in user-readable and understandable format
// extract data from search results
const searchData = await searchResponse.json()
// Narrowed down result - /icd/release/11/2024-01/mms/autocode
console.log(`\nSearched for: ${searchData.searchText}
Results : ${searchData.matchingText}
ICD code: ${searchData.theCode}
Foundation URI: ${searchData.foundationURI}
Relevancy Score: ${searchData.matchScore}
\n`)
// lookup foundationURI - /icd/release/11/2024-01/mms/lookup?foundationUri=http%3A%2F%2Fid.who.int%2Ficd%2Fentity%2F633724732
const lookupUrl = 'https://id.who.int/icd/release/11/2024-01/mms/lookup'
const lookupParams = {
foundationUri: searchData.foundationURI
}
const lookupString = new URLSearchParams(lookupParams)
const lookupEndpoint = `${lookupUrl}?${lookupString}`
const lookupResponse = await fetch(lookupEndpoint, requestOptions)
const lookupData = await lookupResponse.json()
// extract 'browserUrl','title','definition','exclusion','indexTerm'
const diagnosisData = {
browserUrl: lookupData.browserUrl,
diagnosedCondition: lookupData.title["@value"],
generalDetails: lookupData.definition["@value"],
possibleConditions: lookupData.indexTerm.map(term => term.label["@value"]),
excludedConditions: lookupData.exclusion.map(entity => entity.label["@value"])
};
console.log(`\nVisit ICD WHO website for more info : ${diagnosisData.browserUrl}
Diagnosed condition : ${diagnosisData.diagnosedCondition}
General details : ${diagnosisData.generalDetails}
\n`);
for (let term of diagnosisData.possibleConditions) {
console.log('Possible Conditions : ', term);
}
for (let entity of diagnosisData.excludedConditions) {
console.log('Excluded Conditions : ', entity);
}
// Broader results list- /icd/release/11/{releasId}/{linearizationName}/search
// for(word of searchData.words){
// console.log('Possible Condition:', word.label )
// }
// for(entity of searchData.destinationEntities){
// if(entity.score > 0.75){
// console.log(`Title: ${entity.title}\n
// ICD code: ${entity.theCode}\n
// Score: ${entity.score}`)
// }
// }
// check 'words', 'destinationEntities'
// 'destinationEntities'-'title', 'theCode', 'score'
// 'destinationEntities'-'matchingPVs' sometimes have multiple items
}
getTokenAndData()