10
10
import pandas as pd
11
11
from sklearn .cluster import DBSCAN
12
12
13
-
13
+ # API configurations
14
14
app = flask .Flask (__name__ )
15
15
CORS (app )
16
16
app .config ["DEBUG" ] = True
17
17
18
+ # Defining some of the commonly used constants for interaction with Blockchain
18
19
blockchain_url = 'https://kovan.infura.io/v3/' + \
19
20
os .environ ['WEB3_INFURA_PROJECT_ID' ]
20
21
abi = """[{"anonymous": false,"inputs": [{"indexed": false,"internalType": "address","name": "deviceID","type": "address"},{"indexed": false,"internalType": "string","name": "latestCID","type": "string"}],"name": "MappingUpdated","type": "event"},{"inputs": [{"internalType": "address","name": "deviceID","type": "address"},{"internalType": "string","name": "latestCID","type": "string"}],"name": "setLatestCID","outputs": [],"stateMutability": "nonpayable","type": "function"},{"inputs": [],"name": "getDeviceIDsLength","outputs": [{"internalType": "uint256","name": "","type": "uint256"}],"stateMutability": "view","type": "function"},{"inputs": [{"internalType": "uint256","name": "index","type": "uint256"}],"name": "getIDByIndex","outputs": [{"internalType": "address","name": "","type": "address"}],"stateMutability": "view","type": "function"},{"inputs": [{"internalType": "address","name": "deviceID","type": "address"}],"name": "getLatestCID","outputs": [{"internalType": "string","name": "latestCID","type": "string"}],"stateMutability": "view","type": "function"}]"""
21
22
23
+ # Defining some of the commonly used constants for interaction with MoiBit
22
24
conn = http .client .HTTPSConnection ("kfs2.moibit.io" )
23
25
moibit_url = 'https://kfs2.moibit.io/moibit/v0/'
24
26
moibit_header_obj = {
27
29
'content-type' : "application/json"
28
30
}
29
31
30
-
32
+ # Defining the root endpoint
31
33
@app .route ('/' , methods = ['GET' ])
32
34
def home ():
33
35
return "<h1>DICTAO - Decentralized Intelligent Contact Tracing of Animals and Objects</h1><p>This is a simple demonstration of applying blockchain, decentralized storage and AI to solve the COVID-19 crisis.</p>"
34
36
35
37
38
+ # Defining the HTTP 404 response
36
39
@app .errorhandler (404 )
37
40
def page_not_found (e ):
38
41
return "The given ID could not be found" , 404
39
42
40
43
44
+ # Defining the HTTP 500 response
41
45
@app .errorhandler (500 )
42
46
def internal_server_error (e ):
43
47
return e , 500
44
48
45
49
50
+ # Defining the main endpoint
46
51
@app .route ('/api/v0/get_infections' , methods = ['GET' ])
47
52
def get_infections ():
48
53
masterDataSet = []
54
+ # Extracting the input parameters sent by the API calling client
49
55
query_parameters = request .args
56
+
57
+ # Scanning for the input parameter named 'id'
50
58
if 'id' in query_parameters :
59
+ # Reading the value attached to the query parameter 'id'
51
60
id = query_parameters .get ('id' )
52
61
print ("Received ID from the user: " + id )
62
+
63
+ # Checking if the value of 'id' query parameter is null
53
64
if getLatestCID (id ) == "" :
65
+ # Since no value was passed to 'id', we are returning 404
54
66
return page_not_found (404 )
55
67
else :
68
+ # Initiating the web3 object
56
69
w3 = Web3 (Web3 .HTTPProvider (blockchain_url ))
70
+
71
+ # Loading the contract object based on the contract address and ABI
57
72
contract = w3 .eth .contract (
58
73
os .environ ['PROOF_SMART_CONTRACT_ADDRESS' ], abi = abi )
74
+
75
+ # Calling the smart contract function getDeviceIDsLength() in the smart contract
59
76
length = contract .functions .getDeviceIDsLength ().call ()
60
77
print ("Length of the deviceIDs: " + str (length ))
61
78
for i in range (length ):
79
+ # Read the ID/Wallet Address from the contract
62
80
tempId = contract .functions .getIDByIndex (i ).call ()
63
- # print(tempId)
81
+
82
+ # Read the latest CID of the corresponding ID
64
83
tempHash = contract .functions .getLatestCID (tempId ).call ()
65
- # print(tempHash)
84
+
85
+ # Based on the CID, download the latest location history from MoiBit
66
86
jsonData = getJsonDataFromMoiBit (tempHash )
67
- # print(jsonData)
87
+
88
+ '''
89
+ Append each location update to a dataset, so that we obtain one monolithic dataset
90
+ that contains the location history of all the sensors
91
+ '''
68
92
for location in jsonData :
69
93
masterDataSet .append (location )
94
+ '''
95
+ With the location history of each sensor downloaded and extracted,
96
+ let us print the complete dataset
97
+ '''
70
98
print ("Generated live dataset of length: %d" % len (masterDataSet ))
99
+
100
+ # Write the data into a JSON file named "live_dataset.json"
71
101
try :
72
102
with open ('live_dataset.json' , 'x' ) as outfile :
73
103
json .dump (masterDataSet , outfile , indent = 2 )
@@ -76,36 +106,59 @@ def get_infections():
76
106
print ("File Removed!" )
77
107
with open ('live_dataset.json' , 'x' ) as outfile :
78
108
json .dump (masterDataSet , outfile , indent = 2 )
109
+
110
+ # Send the received input ID to identify potential infections
79
111
results = get_infected_ids (id )
112
+
113
+ # With the results obtained, remove the live dataset from the server
80
114
os .remove ("live_dataset.json" )
115
+
116
+ # Build the response object which consists of the input ID and the potentially infected IDs
81
117
response = {
82
118
"id" : id ,
83
119
"potential_infected_ids" : results
84
120
}
121
+
122
+ # Return the JSON data as a response back to the client
85
123
return (jsonify (response ))
86
124
else :
87
125
return "Error: Please specify an ID to identify potential infections."
88
126
89
127
128
+ '''
129
+ get_infected_ids is the function used to identify any potential infections
130
+ made by the given ID. It returns a list of IDs that might be infected by the given ID.
131
+ '''
90
132
def get_infected_ids (input_id ):
133
+ # Reading the live dataset by the file
91
134
basePath = os .path .dirname (os .path .abspath ('live_dataset.json' ))
92
135
dflive = pd .read_json (basePath + '/' + 'live_dataset.json' )
93
136
137
+ # Setting some of the parameters for running DBSCAN algorithm to cluster the datapoints
94
138
epsilon = 0.0018288 # a radial distance of 6 feet, which is medically presribed
95
- min_sample = 2
139
+ min_sample = 2 # Suggesting that a cluster needs to contain a minimum of 2 IDs
140
+
141
+ # Defining the DBSCAN model for clustering the datapoints by passing the parameters and the lat-long input
96
142
model = DBSCAN (eps = epsilon , min_samples = min_sample , metric = 'haversine' ).fit (dflive [['latitude' , 'longitude' ]])
143
+
144
+ # Updating the dataset with the cluster ID for each datapoint
97
145
dflive ['cluster' ] = model .labels_ .tolist ()
98
146
147
+ # Initiating an array for listing all the cluster IDs
99
148
input_id_clusters = []
149
+
150
+ # Scanning the updated dataset for a list of unique cluster IDs
100
151
for i in range (len (dflive )):
101
152
if dflive ['id' ][i ] == input_id :
102
153
if dflive ['cluster' ][i ] in input_id_clusters :
103
154
pass
104
155
else :
105
156
input_id_clusters .append (dflive ['cluster' ][i ])
106
- # print(input_id_clusters)
107
157
158
+ # Initiating the result object. We'll use this to append every potentially infected ID.
108
159
infected_ids = []
160
+
161
+ # Scanning the updated dataset to check if other IDs exist in each cluster where the input ID already exist
109
162
for cluster in input_id_clusters :
110
163
if cluster != - 1 :
111
164
ids_in_cluster = dflive .loc [dflive ['cluster' ] == cluster , 'id' ]
@@ -118,6 +171,10 @@ def get_infected_ids(input_id):
118
171
return infected_ids
119
172
120
173
174
+ '''
175
+ getJsonDataFromMoiBit function is used to download the location history data
176
+ for a given ID from MoiBit
177
+ '''
121
178
def getJsonDataFromMoiBit (cid ):
122
179
pre_payload = {"hash" : cid }
123
180
payload = json .dumps (pre_payload )
@@ -131,6 +188,9 @@ def getJsonDataFromMoiBit(cid):
131
188
return responseObject
132
189
133
190
191
+ '''
192
+ getLatestCID function is used to fetch the latest CID for coressponding IDs
193
+ '''
134
194
def getLatestCID (id ):
135
195
w3 = Web3 (Web3 .HTTPProvider (blockchain_url ))
136
196
contract = w3 .eth .contract (
0 commit comments