ashish-001 commited on
Commit
b23d64e
·
verified ·
1 Parent(s): 726c704

Upload 4 files

Browse files
Files changed (4) hide show
  1. Dockerfile +17 -0
  2. app.py +546 -0
  3. model2.pkl +3 -0
  4. requirements.txt +10 -0
Dockerfile ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.10-slim
2
+
3
+ # Set the working directory
4
+ WORKDIR /app
5
+
6
+ # Copy application code
7
+ COPY . /app
8
+
9
+ # Install dependencies
10
+ RUN apt update && apt install -y build-essential && rm -rf /var/lib/apt/lists/*
11
+ RUN pip install --no-cache-dir -r requirements.txt
12
+
13
+ # Expose the application port
14
+ EXPOSE 7860
15
+
16
+ # Run the application
17
+ CMD ["python", "app.py"]
app.py ADDED
@@ -0,0 +1,546 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dash import Dash, html, dcc, Output, Input, State
2
+ import dash_bootstrap_components as dbc
3
+ import folium
4
+ import folium.map
5
+ from geopy.geocoders import Nominatim
6
+ import requests
7
+ import json
8
+ import pickle
9
+ import pandas as pd
10
+ import jinja2
11
+ from jinja2 import Template
12
+ from folium import Marker
13
+
14
+ model = pickle.load(open('model2.pkl', 'rb'))
15
+
16
+ tmpldata = """<!-- Modified Marker template -->
17
+ {% macro script(this, kwargs) %}
18
+ var {{ this.get_name() }} = L.marker(
19
+ {{ this.location|tojson }},
20
+ {{ this.options|tojson }}
21
+ ).addTo({{ this._parent.get_name() }}).on('click', onClick).on('dragend', function(e) {
22
+ var newLat = e.target.getLatLng().lat;
23
+ var newLng = e.target.getLatLng().lng;
24
+ var markerData = { id: e.target.options.id, lat: parseFloat(newLat), lng: parseFloat(newLng) };
25
+ localStorage.setItem('marker-data-store', JSON.stringify(markerData));
26
+ });
27
+ {% endmacro %}
28
+ """
29
+
30
+ Marker._mytemplate = Template(tmpldata)
31
+
32
+
33
+ def myMarkerInit(self, *args, **kwargs):
34
+ self.__init_orig__(*args, **kwargs)
35
+ self._template = self._mytemplate
36
+
37
+
38
+ Marker.__init_orig__ = Marker.__init__
39
+ Marker.__init__ = myMarkerInit
40
+ m = folium.Map()
41
+
42
+
43
+ app = Dash(__name__, external_stylesheets=[dbc.themes.BOOTSTRAP])
44
+ geolocator = Nominatim(user_agent="delivery_time")
45
+ distance = None
46
+ cords = dict()
47
+ app.title = "Delivery Time Estimator"
48
+ app.layout = html.Div(
49
+ [
50
+ dbc.Row(
51
+ dbc.Col(
52
+ html.H1(
53
+ "Delivery Time Prediction",
54
+ style={
55
+ "textAlign": "center",
56
+ "color": "#2c3e50",
57
+ "marginBottom": "20px",
58
+ },
59
+ ),
60
+ width=12,
61
+ )
62
+ ),
63
+ dbc.Container(
64
+ [
65
+ dbc.Row(
66
+ [
67
+ dbc.Col(
68
+ [
69
+ html.Label("Delivery Person Age"),
70
+ dcc.Input(
71
+ id="delivery_person_age",
72
+ placeholder="Enter Age",
73
+ type="number",
74
+ className="form-control",
75
+ ),
76
+ ],
77
+ width=6,
78
+ ),
79
+ dbc.Col(
80
+ [
81
+ html.Label("Delivery Person Rating"),
82
+ dcc.Input(
83
+ id="delivery_person_rating",
84
+ placeholder="Enter Rating (1-5)",
85
+ type="number",
86
+ min=1,
87
+ max=5,
88
+ className="form-control",
89
+ ),
90
+ ],
91
+ width=6,
92
+ ),
93
+ ],
94
+ className="mb-3",
95
+ ),
96
+ dbc.Row(
97
+ [
98
+ dbc.Col(
99
+ [
100
+ html.Label("Vehicle Type"),
101
+ dcc.Dropdown(
102
+ options=[
103
+ {"label": "Motorcycle",
104
+ "value": "motorcycle"},
105
+ {"label": "Scooter", "value": "scooter"},
106
+ {
107
+ "label": "Electric Scooter",
108
+ "value": "electric_scooter",
109
+ },
110
+ ],
111
+ placeholder="Select Vehicle Type",
112
+ id="vehicle",
113
+ ),
114
+ ],
115
+ width=6,
116
+ ),
117
+ dbc.Col(
118
+ [
119
+ html.Label("Weather Condition"),
120
+ dcc.Dropdown(
121
+ options=[
122
+ {"label": "Fog", "value": "Fog"},
123
+ {"label": "Stormy", "value": "Stormy"},
124
+ {"label": "Cloudy", "value": "Cloudy"},
125
+ {"label": "Sandstorms",
126
+ "value": "Sandstorms"},
127
+ {"label": "Windy", "value": "Windy"},
128
+ {"label": "Sunny", "value": "Sunny"},
129
+ ],
130
+ placeholder="Select Weather Condition",
131
+ id="weather",
132
+ ),
133
+ ],
134
+ width=6,
135
+ ),
136
+ ],
137
+ className="mb-3",
138
+ ),
139
+ dbc.Row(
140
+ [
141
+ dbc.Col(
142
+ [
143
+ html.Label("Road Traffic Density"),
144
+ dcc.Dropdown(
145
+ options=[
146
+ {"label": "Low", "value": "Low"},
147
+ {"label": "Medium", "value": "Medium"},
148
+ {"label": "High", "value": "High"},
149
+ {"label": "Jam", "value": "Jam"},
150
+ ],
151
+ placeholder="Select Traffic Density",
152
+ id="traffic",
153
+ ),
154
+ ],
155
+ width=6,
156
+ ),
157
+ dbc.Col(
158
+ [
159
+ html.Label("Number of Orders"),
160
+ dcc.Dropdown(
161
+ options=[
162
+ {"label": "0", "value": "0"},
163
+ {"label": "1", "value": "1"},
164
+ {"label": "2", "value": "2"},
165
+ {"label": "3", "value": "3"},
166
+ ],
167
+ placeholder="Orders in One Attempt",
168
+ id="multiple_order",
169
+ ),
170
+ ],
171
+ width=6,
172
+ ),
173
+ ],
174
+ className="mb-3",
175
+ ),
176
+ dbc.Row(
177
+ [
178
+ dbc.Col(
179
+ [
180
+ html.Label("Festive Day"),
181
+ dcc.RadioItems(
182
+ options=[
183
+ {"label": "Yes", "value": "Yes"},
184
+ {"label": "No", "value": "No"},
185
+ ],
186
+ inline=True,
187
+ id="festival",
188
+ ),
189
+ ],
190
+ width=6,
191
+ ),
192
+ dbc.Col(
193
+ [
194
+ html.Label("City Type"),
195
+ dcc.Dropdown(
196
+ options=[
197
+ {"label": "Metropolitan",
198
+ "value": "Metropolitian"},
199
+ {"label": "Urban", "value": "Urban"},
200
+ {"label": "Semi-Urban",
201
+ "value": "Semi-Urban"},
202
+ ],
203
+ placeholder="Select City Type",
204
+ id="city",
205
+ ),
206
+ ],
207
+ width=6,
208
+ ),
209
+ ],
210
+ className="mb-3",
211
+ ),
212
+ dbc.Row(
213
+ [
214
+ dbc.Col(
215
+ [
216
+ html.Label("Time of the Day"),
217
+ dcc.Dropdown(
218
+ options=[
219
+ {"label": "Morning", "value": "Morning"},
220
+ {"label": "Afternoon",
221
+ "value": "Afternoon"},
222
+ {"label": "Evening", "value": "Evening"},
223
+ {"label": "Night", "value": "Night"},
224
+ ],
225
+ placeholder="Select Time",
226
+ id="time",
227
+ ),
228
+ ],
229
+ width=6,
230
+ ),
231
+ dbc.Col(
232
+ [
233
+ html.Label("Vehicle Condition"),
234
+ dcc.Dropdown(
235
+ options=[
236
+ {"label": "Smooth", "value": "0"},
237
+ {"label": "Good", "value": "1"},
238
+ {"label": "Average", "value": "2"},
239
+ ],
240
+ placeholder="Select Condition",
241
+ id="condition",
242
+ ),
243
+ ],
244
+ width=6,
245
+ ),
246
+ ],
247
+ className="mb-3",
248
+ ),
249
+ dbc.Row(
250
+ [
251
+ dbc.Col(
252
+ [
253
+ html.Label("Restaurant's Address"),
254
+ dcc.Input(
255
+ id="res_address",
256
+ placeholder="Enter Address (see info ⓘ below)",
257
+ type="text",
258
+ className="form-control",
259
+ ),
260
+ html.Span("ℹ️", id="info-res-address", style={
261
+ "cursor": "pointer", "color": "blue", "marginLeft": "5px"}),
262
+ dbc.Tooltip(
263
+ "If the restaurant address is not found, please provide the nearest location in the format: Street/Place Name, District. You can then drag the icon to the desired location on the map.",
264
+ target="info-res-address",
265
+ placement="right"
266
+ )
267
+ ],
268
+ width=6,
269
+ ),
270
+ dbc.Col(
271
+ [
272
+ html.Label("Receiver's Address"),
273
+ dcc.Input(
274
+ id="rec_address",
275
+ placeholder="Enter Address (see info ⓘ below)",
276
+ type="text",
277
+ className="form-control",
278
+ ),
279
+ html.Span("ℹ️", id="info-rec-address", style={
280
+ "cursor": "pointer", "color": "blue", "marginLeft": "5px"}),
281
+ dbc.Tooltip(
282
+ "If the receiver address is not found, please provide the nearest location in the format: Street/Place Name, District. You can then drag the icon to the desired location on the map.",
283
+ target="info-rec-address",
284
+ placement="right"
285
+ )
286
+ ],
287
+ width=6,
288
+ ),
289
+ ],
290
+ className="mb-3",
291
+ ),
292
+ dbc.Row(
293
+ [
294
+ dbc.Col(
295
+ dbc.Button(
296
+ "Get Map Coordinates",
297
+ id="cordinate-button",
298
+ color="primary",
299
+ n_clicks=0,
300
+ className="d-block mx-auto mt-3",
301
+ ),
302
+ width=6,
303
+ ),
304
+ dbc.Col(
305
+ dbc.Button(
306
+ "Check Delivery Time",
307
+ id="submit-button",
308
+ color="success",
309
+ n_clicks=0,
310
+ className="d-block mx-auto mt-3",
311
+ disabled=True
312
+ ),
313
+ width=6,
314
+ ),
315
+ ],
316
+ className="mb-3",
317
+ ),
318
+ dbc.Row(
319
+ [
320
+ dbc.Col(
321
+ dcc.Loading(
322
+ id="loading-spinner-2",
323
+ type="circle",
324
+ children=html.Div(id="card-container"),
325
+ )
326
+ ),
327
+ ],
328
+ className="mb-3",
329
+ ),
330
+ dbc.Row(
331
+ [
332
+ dbc.Col(
333
+ dcc.Loading(
334
+ id="loading-spinner1",
335
+ type="circle",
336
+ children=html.Div(
337
+ id="card-container-1",
338
+ className="d-flex flex-wrap justify-content-center",
339
+ ),
340
+
341
+ )
342
+ ),
343
+ ],
344
+ className="mb-3",
345
+ ),
346
+ dcc.Store(id="marker-data-store", storage_type="local"),
347
+ ]
348
+ ),
349
+ ],
350
+ style={
351
+ "padding": "20px",
352
+ "backgroundColor": "#f8f9fa",
353
+ "fontFamily": "Arial, sans-serif",
354
+ },
355
+ )
356
+
357
+
358
+ el = folium.MacroElement().add_to(m)
359
+ el._template = jinja2.Template("""
360
+ {% macro script(this, kwargs) %}
361
+
362
+ function onClick(e) {
363
+ var lat = e.latlng.lat;
364
+ var lng = e.latlng.lng;
365
+ var name_mark=e.target.options.id;
366
+ var markerData = {id: name_mark, lat: lat, lng: lng};
367
+
368
+ var newContent = `<p id="latlon">${name_mark}:: ${lat}, ${lng}</p>`;
369
+ e.target.setPopupContent(newContent);
370
+ };
371
+ {% endmacro %}
372
+ """)
373
+
374
+
375
+ def get_prediction(data_point):
376
+ user_input = pd.DataFrame(data_point)
377
+ prediction = model.predict(user_input)
378
+ return prediction[0]
379
+
380
+
381
+ @ app.callback(
382
+ Output('card-container', 'children'),
383
+ Input('submit-button', 'n_clicks'),
384
+ State('delivery_person_age', 'value'),
385
+ State('delivery_person_rating', 'value'),
386
+ State('vehicle', 'value'),
387
+ State('weather', 'value'),
388
+ State('traffic', 'value'),
389
+ State('multiple_order', 'value'),
390
+ State('festival', 'value'),
391
+ State('city', 'value'),
392
+ State('time', 'value'),
393
+ State('condition', 'value'),
394
+ )
395
+ def get_time(n_click, age, rating, vehicle, weather, traffic, order, festive, city, time, condition):
396
+ global cords
397
+ if n_click:
398
+ if cords.get('restaurant_marker', 0) and cords.get('receiver_marker', 0):
399
+ position = {"sources": [{"lat": cords['restaurant_marker'][0], "lon": cords['restaurant_marker'][1]}], "targets": [
400
+ {"lat": cords['receiver_marker'][0], "lon": cords['receiver_marker'][1]}], "costing": "motorcycle"}
401
+ response = requests.get(
402
+ 'https://valhalla1.openstreetmap.de/sources_to_targets', json=position)
403
+ if response.status_code == 200:
404
+ data = response.content
405
+ data = json.loads(data)
406
+ if len(data['sources_to_targets']):
407
+ distance = data['sources_to_targets'][0][0]['distance']
408
+ else:
409
+ distance = -1
410
+ else:
411
+ distance = -1
412
+ else:
413
+ return html.Div([
414
+ html.Br(),
415
+ dbc.Alert(
416
+ "Address is missing",
417
+ id="alert-fade",
418
+ dismissable=True,
419
+ is_open=True,
420
+ color="danger"
421
+ ),
422
+ ])
423
+
424
+ if distance is not None and distance != -1:
425
+ fields = {
426
+ "age": (age, "Delivery Person Age is a required field"),
427
+ "rating": (rating, "Delivery Person Rating is a required field"),
428
+ "vehicle": (vehicle, "Vehicle Type is a required field"),
429
+ "weather": (weather, "Weather Condition is a required field"),
430
+ "traffic": (traffic, "Road Traffic Density is a required field"),
431
+ "order": (order, "Number of orders to be delivered in one attempt is a required field"),
432
+ "festive": (festive, "Whether day is festive or not is a required field"),
433
+ "city": (city, "City type is a required field"),
434
+ "time": (time, "Time of the day is a required field"),
435
+ "condition": (condition, "Condition of the vehicle is a required field"),
436
+ }
437
+ for field_name, (field_value, error_message) in fields.items():
438
+ if not field_value:
439
+ return html.Div([
440
+ html.Br(),
441
+ dbc.Alert(
442
+ f"{error_message}",
443
+ id="alert-fade",
444
+ dismissable=True,
445
+ is_open=True,
446
+ color="danger",
447
+ style={'text-align': 'center'}
448
+ ),
449
+ ])
450
+ data = {'Delivery_person_Age': [int(age)], 'Delivery_person_Ratings': [float(rating)], 'distance': [float(distance)], 'Type_of_vehicle': [vehicle], 'Weather': [weather],
451
+ 'Road_traffic_density': [traffic], 'multiple_deliveries': [int(order)], 'Festival': [festive], 'City': [city], 'time of day': [time], 'Vehicle_condition': [int(condition)]}
452
+ predicted_time = get_prediction(data)
453
+ return html.Div([
454
+ html.Br(),
455
+ dbc.Alert(
456
+ f"Predicted time for delivering the food: {int(predicted_time)} minutes",
457
+ id="alert-fade",
458
+ dismissable=True,
459
+ is_open=True,
460
+ color="success",
461
+ style={'text-align': 'center'}
462
+ ),
463
+ ])
464
+ else:
465
+ return html.Div([
466
+ html.Br(),
467
+ dbc.Alert(
468
+ "Please set the map coordinates",
469
+ id="alert-fade",
470
+ dismissable=True,
471
+ is_open=True,
472
+ color="danger"
473
+ ),
474
+ ])
475
+
476
+
477
+ @ app.callback(
478
+ Output('submit-button', 'disabled'),
479
+ Output('card-container-1', 'children'),
480
+ Input('cordinate-button', 'n_clicks'),
481
+ State('res_address', 'value'),
482
+ State('rec_address', 'value')
483
+
484
+
485
+ )
486
+ def get_map_cordinates_and_distance(click, res_add, rec_add):
487
+ global distance
488
+ global cords
489
+ if not click:
490
+ return True, html.Div([
491
+ html.P("Click 'Get map coordinates' after entering the addresses."),
492
+ ], style={'color': 'gray'})
493
+ if not res_add or not rec_add:
494
+ return True, html.Div([
495
+ dbc.Alert(
496
+ "Both restaurant and receiver addresses must be entered.",
497
+ id="alert-missing-address",
498
+ dismissable=True,
499
+ is_open=True,
500
+ color="danger"
501
+ ),
502
+ ])
503
+ res_coordinates = geolocator.geocode(res_add)
504
+ rec_coordinates = geolocator.geocode(rec_add)
505
+
506
+ if not res_coordinates:
507
+ return True, html.Div([
508
+ html.P("Enter correct restaurant address"),
509
+ ])
510
+ if not rec_coordinates:
511
+ return True, html.Div([
512
+ html.P("Enter correct receiver address"),
513
+ ])
514
+ cords = {
515
+ 'restaurant_marker': [res_coordinates.latitude, res_coordinates.longitude],
516
+ 'receiver_marker': [rec_coordinates.latitude, rec_coordinates.longitude],
517
+ }
518
+
519
+ folium.Marker(
520
+ [cords['restaurant_marker'][0], cords['restaurant_marker'][1]], popup=f"<p id='reslatlon'>Location of Restaurant: {cords['restaurant_marker'][0]},{cords['restaurant_marker'][1]}</p>", icon=folium.Icon(color='green', icon='utensils', prefix='fa'), id="restaurant_marker", tooltip="Click for location", draggable=True).add_to(m)
521
+ folium.Marker(
522
+ [cords['receiver_marker'][0], cords['receiver_marker'][1]], popup=f"<p id='reclatlon'>Location of Receiver: {cords['receiver_marker'][0]},{cords['receiver_marker'][1]}</p>", icon=folium.Icon(color='red', icon='house', prefix='fa'), tooltip="Click for location", draggable=True, id="receiver_marker").add_to(m)
523
+ lats = [cords['restaurant_marker'][0], cords['receiver_marker'][0]]
524
+ longs = [cords['restaurant_marker']
525
+ [1], cords['receiver_marker'][1]]
526
+ bounds = [[min(lats), min(longs)], [max(lats), max(longs)]]
527
+ m.fit_bounds(bounds=bounds)
528
+
529
+ return False, html.Iframe(srcDoc=m.get_root().render(), style={'width': '80%', 'height': '500px'})
530
+
531
+
532
+ @ app.callback(
533
+ Input('marker-data-store', 'data'),
534
+ Input('cordinate-button', 'n_clicks'),
535
+ prevent_initial_call=True
536
+ )
537
+ def update_output(store_data, n_clicks):
538
+ global cords
539
+ if n_clicks:
540
+ if store_data:
541
+ cords[store_data['id']] = [
542
+ store_data.get('lat'), store_data.get('lng')]
543
+
544
+
545
+ if __name__ == '__main__':
546
+ app.run(host='0.0.0.0', port=7860)
model2.pkl ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:78fcee20b05ffe6b8032d664e8c587819503b7e8b3534642b8e5b653daac4cf4
3
+ size 10719801
requirements.txt ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ scikit-learn==1.5.1
2
+ xgboost==2.0.2
3
+ dash==2.18.1
4
+ dash-bootstrap-components==1.6.0
5
+ folium==0.18.0
6
+ geopy==2.4.1
7
+ requests==2.31.0
8
+ pandas==2.2.2
9
+ Jinja2==3.1.2
10
+