From c560de266caad6db97e58757ca43e8558c103c01 Mon Sep 17 00:00:00 2001 From: Anson Bridges Date: Sat, 18 Nov 2023 06:18:23 -0500 Subject: csv import, manual visiting --- .../__pycache__/datastructs.cpython-311.pyc | Bin 7348 -> 7356 bytes dashboard_website/__pycache__/db.cpython-311.pyc | Bin 11189 -> 12642 bytes .../__pycache__/router.cpython-311.pyc | Bin 18525 -> 18700 bytes dashboard_website/dashboard.py | 35 +++++++++++ dashboard_website/db.py | 68 +++++++++++++++------ dashboard_website/dirt.csv | 68 +++++++++++++++++++++ dashboard_website/router.py | 7 ++- dashboard_website/savefile.csv | 1 + dashboard_website/static/js/controls.js | 42 +++++++++++++ dashboard_website/static/js/dashboard.js | 20 +++++- dashboard_website/templates/controls.html | 26 ++++++++ dashboard_website/templates/index.html | 2 +- 12 files changed, 244 insertions(+), 25 deletions(-) create mode 100644 dashboard_website/dirt.csv create mode 100644 dashboard_website/savefile.csv create mode 100644 dashboard_website/static/js/controls.js create mode 100644 dashboard_website/templates/controls.html diff --git a/dashboard_website/__pycache__/datastructs.cpython-311.pyc b/dashboard_website/__pycache__/datastructs.cpython-311.pyc index 43fc8d9..95d05af 100644 Binary files a/dashboard_website/__pycache__/datastructs.cpython-311.pyc and b/dashboard_website/__pycache__/datastructs.cpython-311.pyc differ diff --git a/dashboard_website/__pycache__/db.cpython-311.pyc b/dashboard_website/__pycache__/db.cpython-311.pyc index 48ee159..2312bc2 100644 Binary files a/dashboard_website/__pycache__/db.cpython-311.pyc and b/dashboard_website/__pycache__/db.cpython-311.pyc differ diff --git a/dashboard_website/__pycache__/router.cpython-311.pyc b/dashboard_website/__pycache__/router.cpython-311.pyc index 1e21e0e..f94a179 100644 Binary files a/dashboard_website/__pycache__/router.cpython-311.pyc and b/dashboard_website/__pycache__/router.cpython-311.pyc differ diff --git a/dashboard_website/dashboard.py b/dashboard_website/dashboard.py index 06af267..7d0d920 100644 --- a/dashboard_website/dashboard.py +++ b/dashboard_website/dashboard.py @@ -215,6 +215,15 @@ def getLatestInfo(): return jsonify(data) +@app.route("/addClue", methods=['POST']) +def addClueWeb(): + content = request.get_json() + + if not ('clue_name' in content and 'longitude' in content and 'latitude' in content and 'clue_info' in content): + return jsonify({'status' : "ERROR 1"}) + + return jsonify({'status' : "OK",}) + # main page # GET = get main page @@ -223,6 +232,32 @@ def siteIndex(): #clues = db.getClues(); bikes = db.getBikes() return render_template("index.html")#, clues=clues, bikes=bikes) +# add csv, download as csv +@app.route("/controls", methods=['GET', 'POST']) +def siteControls(): + if request.method == "GET": + return render_template("controls.html") + if request.method == "POST": + cmd = request.form.get('command') + print(cmd) + if cmd == "downloadSave": + print("send") + db.save() + return send_from_directory(".", "savefile.csv", as_attachment=True) + elif cmd == "loadDirty": + dirty_csv = request.files['dirtyfile'] + dirty_csv.save("dirt.csv") + if db.loadDirty("dirt.csv") != 0: + return jsonify({"status" : "ERROR"}) + return jsonify({"status" : "OK"}) + elif cmd == "loadClean": + dirty_csv = request.files['cleanfile'] + dirty_csv.save("clean.csv") + if db.load("clean.csv") != 0: + return jsonify({"status" : "ERROR"}) + return jsonify({"status" : "OK"}) + + return render_template("controls.html") if __name__ == "__main__": diff --git a/dashboard_website/db.py b/dashboard_website/db.py index 6a638e7..166ac7a 100644 --- a/dashboard_website/db.py +++ b/dashboard_website/db.py @@ -48,6 +48,7 @@ def updateRoutes_background(): # run in thread due to long runtime def updateRoutes(): # if necessary global currently_updating if not currently_updating: + save() currently_updating = True t = Thread(target=updateRoutes_background) t.start() @@ -155,18 +156,20 @@ def deleteClue(clue_name): def visitClue(clue_name): + global clues_last_changed for clue in clues: if clue.name == clue_name: if clue.status == "VISITED": return 3 # already visited clue.visit() clues_last_changed = time.time() - # updateRoutes() + updateRoutes() return 0 # OK return 2 # no clue found def visitClueTeam(team_name, clue_name): + global clues_last_changed b = None for bike in bikes: if bike.name == team_name: @@ -185,6 +188,7 @@ def visitClueTeam(team_name, clue_name): return 5 # clue not found # if visited clue is the expected one (current target) + # no need to recalculate if clue_name == b.target_name: if c.distanceTo(b) < CLUE_MIN_DISTANCE: return 3 # too far away @@ -195,6 +199,7 @@ def visitClueTeam(team_name, clue_name): # otherwise c.visit() clues_last_changed = time.time() + updateRoutes() # must be updated due to unexpected visitation def load(filename=None): @@ -204,8 +209,9 @@ def load(filename=None): :return: None """ # if there is no filename, wipe all clues - if filename is None: + if filename == None: clues.clear() + filename = "savefile.csv" # otherwise, load from file with open(filename, newline='') as f: @@ -215,13 +221,46 @@ def load(filename=None): next(csvreader) for row in csvreader: - name = row[0] - latitude = row[1] - longitude = row[2] - info = row[3] - status = row[4] + try: + name = row[0] + latitude = row[1] + longitude = row[2] + info = row[3] + status = row[4] + + clues.append(Clue(latitude, longitude, name, info, status)) + except: + return 1 + clues_last_changed = time.time() + updateRoutes() + return 0 + +def loadDirty(filename=None): + global clues_last_changed + if filename == None: + return + + # otherwise, load from file + with open(filename, newline='') as f: + csvreader = csv.reader(f, delimiter=',', quotechar='"') - clues.append(Clue(latitude, longitude, name, info, status)) + # skip header row + next(csvreader) + for row in csvreader: + try: + name = row[0] + info = row[2] + latlong = row[3].split(",") + if len(latlong) != 2: continue + latitude = float(latlong[0]) + longitude = float(latlong[1]) + + clues.append(Clue(latitude, longitude, name, info, "UNVISITED")) + except: + return 1 + clues_last_changed = time.time() + updateRoutes() + return 0 def save(): @@ -237,15 +276,4 @@ def save(): csvwriter.writerow([clue.name, clue.latitude, clue.longitude, clue.info, clue.status]) -# junk for testing -with open("all_clues.csv", newline='') as f: - csvreader = csv.reader(f, delimiter=',', quotechar='"') - i = 1 - for row in csvreader: - coords = row[1].split(",") - coords[0] = float(coords[0]); - coords[1] = float(coords[1]); - - newClue = Clue(coords[0], coords[1], f"Clue #{i}", row[0], "UNVISITED" if i < 100 else "VISITED") - clues.append(newClue) - i += 1 +load() \ No newline at end of file diff --git a/dashboard_website/dirt.csv b/dashboard_website/dirt.csv new file mode 100644 index 0000000..08ab5cd --- /dev/null +++ b/dashboard_website/dirt.csv @@ -0,0 +1,68 @@ +Clue ID,Clue,Name,"Latitude, Longitude (right click near place on google maps, then click the coordinates to copy)",, +A1,"1) Where Andrew, Tom, and Toby might toss a frisbee PETERS PARK BOSTON",Peters Park,"42.3430402738135, -71.0675801105357",, +A2,2) It's not North of Washington Street.... SOWA → South of Washington Street?,SoWa Market(?),,, +A3,"3) Blues, Latin jazz salsa, jazz xa, funk x3, 24/7/365 Wally’s Cafe Jazz club",Wally's Cafe Jazz Club,"42.340735169280684, -71.0822142949978",, +A4,"4) Not to be confused with the Jesuit college in Worcester, this is a cathedral Cathedral",Cathedral of the Holy Cross,"42.340965725249276, -71.07004200293923",, +A5,5) Lilli Ann K Rosenberg brainchild in the South End,Betances Mural (80%),"42.34236478201366, -71.07314991031272",, +A6,"6) Not an above-ground railroad, she is remembered as one of the conductors",Harriet Tubman Memorial,"42.34355826498339, -71.0779098454636",, +A7,7) Halloween's Michael + Community's Señor: ,Myers+Chang,"42.343917124461065, -71.06620549483627",, +A8,8) This diner has a secret,Hidden Kitchen,"42.33836232114676, -71.0667887997758",, +A9,9) Need budgeting advice? Take a page out of their book,,,, +A10,"10) Go for the Spanish dancing, stay for the Spanish food",La Fabrica Central Restaurant,"42.363845469421676, -71.10129788828729",, +A11,11) A place Petunia and Vernon would love to share a cup of coffee,"Dudley Cafe , Dudley Square","42.33000580911709, -71.08345739566941",, +A12,12) The namesake of this house suggested bullets or ballots,Malcolm X House,"42.321503645221576, -71.0863561083245",, +A13,13) A station honoring an ancient Nile kingdom → ,"Nubian Station, Roxbury","42.329719158213535, -71.08393017974034",, +A14,"14) The sun, but in French.",soleil,"42.32995937830152, -71.08425706494715",, +A15,15) Taking down bear proof cages is a lot harder than putting them up,old bear pens,"42.31163492909362, -71.0944883387719",, +A16,"16) A high school for mayo, smoked turkey, cucumbers, tomatoes, and sprouts",,,, +A17,17) Where to go when you need spaghetti in a hurry on the hill,Lily's Gourmet Pasta Express,"42.33240052352865, -71.10001875238213",, +A18,18) The Jamaica Plain Tuesday Club is its steward,Loring Greenough House,"42.30940190779075, -71.11503165360074",, +A19,19) Spooner finds 2020 chicago mayor at this theater (9 letters),Strand Theatre,"42.31599303331773, -71.0660247",, +A20,"20) You won't find cows or pigs in this barn, but maybe a hot meal instead",noodle barn (?),"42.31145648101414, -71.11454193944768",, +A21,21) The Crimson's green showcase,Harvard Arboretum,"42.30758360954152, -71.11986574437587",, +A22,22) A not so functional seat to enjoy pond views,JAMACIA POND BENCH,"42.31703238067602, -71.1172176327592",, +A23,"23) Grab a book from this famous labor organizer, it's plainly not a Haymarket affair",Lucy Parsons Center (Jamaica Plain),"42.32234399461923, -71.10765946762163",, +A24,24) Go to this fire station to get an ice cold treat,fire station turned JP Licks,"42.312828161837565, -71.1142521044243",, +A25,"25) Sorta like the death of an author, but (mil)more in bronze",Death and the Sculptor,,,"42.29783644453621, -71.10768546216663" +A26,26) SD.2702 was recently passed here,Massachusetts State House,"42.35772690789592, -71.0636244852727",, +A27,"27) Mae's performing here either today or tomorrow -> 158 Brighton Ave, Allston, MA 02134",Brighton Music Hall,"42.35296368437526, -71.13261242438084",, +A28,"28) I don't know much about their baked goods, but the flag is a big plus",SWISS BAKERY ALSTON,"42.3632259246665, -71.12855843461686",, +A29,"29) If you're looking for good Asian fusion, you'll find a bonch on Brighton Avenue",Bonchon Boston,"42.35298420423782, -71.13089261430888",, +A30,"30) Absalom, absalom! Listen closely for the sound and the fury at this memorial","Anderson bridge: a small brass plaque, the size of one brick, that is located on the +brick wall of the Eastern (Weld Boathouse) side of the bridge, just +north of the middle of the bridge span, about eighteen inches from the +ground in a small alcove. It reads: +""QUENTIN COMPSON +Drowned in the odour of honeysuckle. +1891-1910""","42.36898885010578, -71.12306457136677",, +A31,31) Don't go here for rescue from arson - even if you are only at O'Brien's,Boston Fire Dept. Station 41,"42.353802, -71.136116",, +A32,32) CSM and IVM provide the name for this BC museum,McMullen Museum of art,"42.34038115716941, -71.16265204351588",, +A33,33) A hammer thrower resides peacefully outside a former school named after Big Lub,Hal Connolly Statue,"42.35037729554579, -71.14555952509022",, +A34,34 ) This Catalan restaurant will bring you to task ,Tasca Restaurant,"42.3434052435984, -71.14279038706111",, +A35,35) The students here seem like they'll have a Bright future,Brighton High School,"42.34965767795442, -71.14606621964128",, +A36,36) Going to the chapel and it's 1959 ,Harvard Class of 1959 Chapel,"42.36580905967968, -71.12374919164488",, +A37,"37) This monument wasn't made by its subject, but it could have been",,,, +A38,"38) Quack quack quack, their home on the Fens",agassiz road duck house,"42.34341395011007, -71.09317746727483",, +A39,39) The less controversial MLK statue,MLK statue on BU campus,"42.35036326253947, -71.10650807481497",, +A40,"40) This hotel kicked out St. George and caused a Black Sox scandal, Bucko!",Boston Hotel Buckminster,"42.348465223671944, -71.09776617622576",, +A41,"41) Vitruvian, Viridian. Potato, potato. Find this place where all the people of Fenway can meet",The Viridian (Apartment Building that has Blaze Pizza),"42.34453026994564, -71.09720444433195",, +A42,42) This pizza place loves fire so much they put it in the name!,Land of Fire Pizzeria,"42.34138871428725, -71.14657093175214",, +A43,43) A BU student's go-to for Indian food,India Quality Restaurant,"42.3485725720217, -71.0942113926108",, +A44,44) The statue of the son of the red,MAYBE Ted Williams Statue ,"42.34605480640728, -71.0960390033173",, +A45,45) This citrus isn't supposed to be that color!,,,, +A46,46) Boston Terriers love getting their tan on here,BU Beach,"42.35116095548625, -71.10606134524427",, +A47,47) So she ran away in her sleep and dreamed of this rock,Paradise Rock Club (Commonwealth),"42.3518271762187, -71.11983863137432",, +A48,48) Has better ratings than the noun motel or the adverb inn,The Verb Hotel,"42.34517137203154, -71.09676153399613",, +A49,49) Supposedly the oldest playground in America,Cypress Street Playground,"42.3315920224197, -71.12571559999999",, +A50,50) Ook een boek van Ann Patchett,The Dutch House,"42.335982955313646, -71.11231902990166",, +A51,51) The home of the nation's best parkmaker,Frederick Law Olmstead National Historic Site,"42.32590914866024, -71.13228373433928",, +A52,52) This Brookline shop might forge their own tomes,Brookline Booksmith,"42.342764551151554, -71.12168301640884",, +A53,53) we we we we should should should should cross cross cross cross here here here here,Echo Bridge,"42.31487124359676, -71.22693938547769",, +A54,54) This weekend it's hosting a Thanksgiving with Mary Baker Eddy,Longyear Museum,"42.32485823589608, -71.16189103410989",, +A55,55) Steam engines so big they ll leave you crying,Waterworks Museum,"42.3320010747946, -71.15563010527421",, +,,,,, +,,,,, +,,,,, +,,,,, +,Japanese Temple Bell at 9:30 in the Fens (right across the first foot bridge),,,, +,"42.34132619174766, -71.09428257118488",,,, \ No newline at end of file diff --git a/dashboard_website/router.py b/dashboard_website/router.py index 5d5a909..1a90a9e 100644 --- a/dashboard_website/router.py +++ b/dashboard_website/router.py @@ -2,13 +2,14 @@ import numpy as np import requests from sklearn.cluster import KMeans import time -from datetime import datetime +import datetime from datastructs import * host = "http://acetyl.net:5000" # queries acetyl.net:5000, the OSRM engine +endtime = datetime.datetime(2023, 11, 18, 18, 35) # 11/18/2023 6:35pm # external facing functions @@ -77,6 +78,8 @@ def cluster_and_optimize(clues: [Clue], bikes: [Bike], end: Point, time_diff=0.2 :param n: the number of routes to create :return: a list of lists of clues (ordered by position on route), and a list of json route geojsons """ + # OVERRIDE MAX TIME + max_time = datetime.datetime.now() - endtime routes = [clues] # one bike = one set of routes. only need to remove the faraway waypoints if len(bikes) > 1: # Create a new column with normalized gps coordinates and centroids @@ -106,7 +109,7 @@ def cluster_and_optimize(clues: [Clue], bikes: [Bike], end: Point, time_diff=0.2 geometries.append(route_json['trips'][0]['geometry']['coordinates']) route_waypoints.append(route_json['waypoints']) eta = time.time() + route_json['trips'][0]['duration'] + 90 * len(route) - eta_str = datetime.fromtimestamp(eta).strftime("%I:%M:%S%p") + eta_str = datetime.datetime.fromtimestamp(eta).strftime("%I:%M:%S%p") times.append(eta_str) # Use the waypoint_index to reorder each route diff --git a/dashboard_website/savefile.csv b/dashboard_website/savefile.csv new file mode 100644 index 0000000..84b6c30 --- /dev/null +++ b/dashboard_website/savefile.csv @@ -0,0 +1 @@ +name,latitude,longitude,info,status diff --git a/dashboard_website/static/js/controls.js b/dashboard_website/static/js/controls.js new file mode 100644 index 0000000..3d81032 --- /dev/null +++ b/dashboard_website/static/js/controls.js @@ -0,0 +1,42 @@ +// uses functions in utils.js +var host = window.location.protocol + "//" + window.location.host; + +function downloadCurrent(){ + call("downloadSave"); +} + +// load and append dirty file +function loadDirty(){ + call("loadDirty", "dirty"); +} + +// load save file (clean) +function loadSave(){ + call("loadSave", "clean"); +} + +function call(command, formid=""){ + var formData; + if (formid == "") { + formData = new FormData(); + }else { + formData = new FormData(document.getElementById(formid)); + } + + formData.append("command", command); + console.log(formData); + + fetch(host+'/controls', { + method: "POST", + body: formData + }).then( res => res.blob() ) + .then( blob => { + var file = window.URL.createObjectURL(blob); + window.location.assign(file);}); + //.then((response) => response.json()) + //.then((json) => handleCallResponse(json)); +} + +function handleLatestInfo(json){ + if(json['status'] != "OK")alert("Error."); +} \ No newline at end of file diff --git a/dashboard_website/static/js/dashboard.js b/dashboard_website/static/js/dashboard.js index fba7196..4ce6fac 100644 --- a/dashboard_website/static/js/dashboard.js +++ b/dashboard_website/static/js/dashboard.js @@ -123,13 +123,28 @@ function drawClues(){ for (var i = 0; i < clues.length; i++) { var tempIcon = visitedIcon; if (clues[i]['clue_status'] == "UNVISITED") tempIcon = unvisitedIcon; - var clueMarker = L.marker([clues[i]['latitude'], clues[i]['longitude']], {icon: tempIcon}).bindPopup(clues[i]['clue_name'] + ": " + clues[i]['clue_info']); + var popupdiv = document.createElement('p'); + popupdiv.innerHTML = "" + clues[i]['clue_name'] + ": " + clues[i]['clue_info'] + "" + var clueMarker = L.marker([clues[i]['latitude'], clues[i]['longitude']], {icon: tempIcon}).bindPopup(popupdiv); clue_rels[clues[i]['clue_name']] = clueMarker; if (clues[i]['clue_status'] == "UNVISITED") unvisited_clues_m.addLayer(clueMarker); else visited_clues_m.addLayer(clueMarker); } } +function visitClue(clue_name){ + console.log("visiting: "+clue_name); + fetch(host+'/visitClueGeneric', { + method: "POST", + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + body: JSON.stringify({ "clue_name" : clue_name })}) + .then((response) => response.json()) + .then((json) => console.log(json)); +} + function addClue(){ var long = parseFloat(document.getElementById("new_clue_longitude").value); var lat = parseFloat(document.getElementById("new_clue_latitude").value); @@ -252,4 +267,5 @@ window.onload = function() { layerControl.addOverlay(bikes_m, "Bikes"); layerControl.addTo(map); requestLatestInfo(); -} \ No newline at end of file +} + diff --git a/dashboard_website/templates/controls.html b/dashboard_website/templates/controls.html new file mode 100644 index 0000000..2ad3adc --- /dev/null +++ b/dashboard_website/templates/controls.html @@ -0,0 +1,26 @@ + + + + + MMCH Controls + + + + + + + Back
+
+
+ + + +

+
+ + + +
+ + + \ No newline at end of file diff --git a/dashboard_website/templates/index.html b/dashboard_website/templates/index.html index 73f9f22..d4f8196 100644 --- a/dashboard_website/templates/index.html +++ b/dashboard_website/templates/index.html @@ -144,7 +144,7 @@
ROUTE INFO
-
+
-- cgit v1.2.3