sahar-yaccov commited on
Commit
a8fb6c8
·
verified ·
1 Parent(s): 52292f3

Upload 16 files

Browse files
app/.DS_Store ADDED
Binary file (6.15 kB). View file
 
app/components/__pycache__/bus_stop_search.cpython-312.pyc ADDED
Binary file (1.45 kB). View file
 
app/components/alert.py ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/components/alert.py
2
+ import streamlit as st
3
+
4
+ def show_alert(distance_minutes: float):
5
+ """
6
+ Show alert if user is 2 minutes away
7
+ """
8
+ if distance_minutes <= 2:
9
+ st.warning("🚨 You are about 2 minutes away from your destination!")
10
+ if st.button("I've arrived"):
11
+ return True
12
+ return False
app/components/bus_stop_search.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/components/bus_stop_search.py
2
+ import streamlit as st
3
+ from geopy.geocoders import Nominatim
4
+ from typing import Tuple
5
+
6
+ # יצירת geolocator
7
+ geolocator = Nominatim(user_agent="bus_stop_app")
8
+
9
+ def search_station(name: str) -> Tuple[float,float]:
10
+ """
11
+ Fetch bus stop location by name using OpenStreetMap Nominatim
12
+ """
13
+ location = geolocator.geocode(name , timeout=10)
14
+ if location:
15
+ return location.latitude, location.longitude
16
+ else:
17
+ return None
18
+
19
+ def bus_stop_search_ui() -> Tuple[float,float]:
20
+ """
21
+ Streamlit UI for searching destination
22
+ """
23
+ query = st.text_input("Enter your destination:", "")
24
+ if query:
25
+ coords = search_station(query)
26
+ if coords:
27
+ st.success(f"Found {query} at {coords[0]:.6f}, {coords[1]:.6f}")
28
+ return coords
29
+ else:
30
+ st.warning("Station not found")
31
+ return None
app/components/favorites.py ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/components/favorites.py
2
+ import streamlit as st
3
+
4
+ def load_favorites():
5
+ return st.session_state.get("favorites", [])
6
+
7
+ def add_favorite(station_name: str):
8
+ if "favorites" not in st.session_state:
9
+ st.session_state["favorites"] = []
10
+ if station_name not in st.session_state["favorites"]:
11
+ st.session_state["favorites"].append(station_name)
12
+
13
+ def remove_favorite(station_name: str):
14
+ if "favorites" in st.session_state and station_name in st.session_state["favorites"]:
15
+ st.session_state["favorites"].remove(station_name)
16
+
17
+ def favorites_ui():
18
+ favorites = load_favorites()
19
+ st.subheader("Favorites")
20
+ for fav in favorites:
21
+ st.write(f"- {fav}")
app/components/map_view.py ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/components/map_view.py
2
+ import streamlit as st
3
+ import folium
4
+ from streamlit_folium import st_folium
5
+ from typing import Tuple
6
+
7
+ def show_map(user_location: Tuple[float,float], destination: Tuple[float,float]):
8
+ """
9
+ Displays the map with user's current location and destination
10
+ """
11
+ m = folium.Map(location=user_location, zoom_start=13)
12
+
13
+ # User location marker
14
+ folium.Marker(
15
+ location=user_location,
16
+ popup="You are here",
17
+ icon=folium.Icon(color="blue")
18
+ ).add_to(m)
19
+
20
+ # Destination marker
21
+ folium.Marker(
22
+ location=destination,
23
+ popup="Destination",
24
+ icon=folium.Icon(color="red")
25
+ ).add_to(m)
26
+
27
+ # Line between current location and destination
28
+ folium.PolyLine([user_location, destination], color="green").add_to(m)
29
+
30
+ st_folium(m, width=700, height=500)
app/hooks/__pycache__/use_alert.cpython-312.pyc ADDED
Binary file (745 Bytes). View file
 
app/hooks/__pycache__/use_distance.cpython-312.pyc ADDED
Binary file (1.71 kB). View file
 
app/hooks/__pycache__/use_location.cpython-312.pyc ADDED
Binary file (2.99 kB). View file
 
app/hooks/use_alert.py ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/hooks/use_alert.py
2
+ import streamlit as st
3
+
4
+ def check_alert(time_to_destination_min: float) -> bool:
5
+ """
6
+ Trigger alert if time to destination <= 2 minutes
7
+ Returns True if user pressed "I've arrived"
8
+ """
9
+ if time_to_destination_min <= 2:
10
+ st.warning("🚨 You are about 2 minutes away from your destination!")
11
+ arrived = st.button("I've arrived")
12
+ if arrived:
13
+ return True
14
+ return False
app/hooks/use_distance.py ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/hooks/use_distance.py
2
+ import math
3
+ from typing import Tuple
4
+
5
+ def haversine(coord1: Tuple[float,float], coord2: Tuple[float,float]) -> float:
6
+ """
7
+ Calculate distance in km between two GPS points using Haversine formula
8
+ """
9
+ lat1, lon1 = coord1
10
+ lat2, lon2 = coord2
11
+ R = 6371 # Earth radius in km
12
+
13
+ phi1 = math.radians(lat1)
14
+ phi2 = math.radians(lat2)
15
+ delta_phi = math.radians(lat2 - lat1)
16
+ delta_lambda = math.radians(lon2 - lon1)
17
+
18
+ a = math.sin(delta_phi/2)**2 + math.cos(phi1)*math.cos(phi2)*math.sin(delta_lambda/2)**2
19
+ c = 2*math.atan2(math.sqrt(a), math.sqrt(1-a))
20
+
21
+ return R * c
22
+
23
+ def estimate_time(distance_km: float, speed_kmh: float = 30) -> float:
24
+ """
25
+ Estimate time to destination in minutes
26
+ Default speed: 30 km/h
27
+ """
28
+ return (distance_km / speed_kmh) * 60
app/hooks/use_location.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import requests
2
+ import threading
3
+ import time
4
+
5
+ API_URL = "http://127.0.0.1:8000/location"
6
+ IP_GEO_URL = "http://ip-api.com/json"
7
+
8
+ class GPSHandler:
9
+ def __init__(self, update_interval=10):
10
+ self.last_location = None
11
+ self.update_interval = update_interval # שניות
12
+ self._updating = False
13
+
14
+ # --- מקבל את הקואורדינטות הנוכחיות ---
15
+ def get_location(self):
16
+ if self.last_location:
17
+ return self.last_location
18
+ try:
19
+ res = requests.get(IP_GEO_URL, timeout=5)
20
+ data = res.json()
21
+ if data.get("status") == "success":
22
+ lat, lon = data["lat"], data["lon"]
23
+ self.last_location = (lat, lon)
24
+ self.send_location(lat, lon)
25
+ return self.last_location
26
+ except Exception:
27
+ pass
28
+ return None
29
+
30
+ # --- מדפיס את הקואורדינטות ---
31
+ def print_location(self):
32
+ if self.last_location:
33
+ print(f"[GPS] Latitude: {self.last_location[0]:.6f}, Longitude: {self.last_location[1]:.6f}")
34
+ else:
35
+ print("[GPS] Location not available.")
36
+
37
+ # --- שולח לשרת ---
38
+ def send_location(self, lat, lon):
39
+ try:
40
+ requests.post(API_URL, json={"lat": lat, "lon": lon}, timeout=5)
41
+ except Exception:
42
+ pass
43
+
44
+ # --- עדכון GPS אוטומטי כל X שניות ---
45
+ def update_gps(self):
46
+ self._updating = True
47
+ def _update():
48
+ if not self._updating:
49
+ return
50
+ self.get_location()
51
+ self.print_location()
52
+ # קריאה מחודשת אחרי self.update_interval שניות
53
+ threading.Timer(self.update_interval, _update).start()
54
+ _update()
55
+
56
+ # --- עצירת עדכון אוטומטי ---
57
+ def stop_update(self):
58
+ self._updating = False
app/utils/haversine.py ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/utils/haversine.py
2
+ import math
3
+ from typing import Tuple
4
+
5
+ def haversine(coord1: Tuple[float,float], coord2: Tuple[float,float]) -> float:
6
+ """
7
+ Calculate distance in kilometers between two GPS coordinates using Haversine formula
8
+ coord1, coord2: (lat, lon)
9
+ Returns distance in km
10
+ """
11
+ lat1, lon1 = coord1
12
+ lat2, lon2 = coord2
13
+ R = 6371 # Earth's radius in km
14
+
15
+ phi1 = math.radians(lat1)
16
+ phi2 = math.radians(lat2)
17
+ delta_phi = math.radians(lat2 - lat1)
18
+ delta_lambda = math.radians(lon2 - lon1)
19
+
20
+ a = math.sin(delta_phi/2)**2 + math.cos(phi1)*math.cos(phi2)*math.sin(delta_lambda/2)**2
21
+ c = 2 * math.atan2(math.sqrt(a), math.sqrt(1-a))
22
+
23
+ distance = R * c
24
+ return distance
static/index.html ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8" />
5
+ <title>Bus Stop Alert</title>
6
+ </head>
7
+ <body>
8
+
9
+ <h2>Bus Stop Alert</h2>
10
+ <button onclick="sendLocation()">Send my location</button>
11
+ <p id="status"></p>
12
+
13
+ <script>
14
+ function sendLocation() {
15
+ navigator.geolocation.getCurrentPosition(
16
+ (pos) => {
17
+ fetch("/location", {
18
+ method: "POST",
19
+ headers: { "Content-Type": "application/json" },
20
+ body: JSON.stringify({
21
+ lat: pos.coords.latitude,
22
+ lon: pos.coords.longitude
23
+ })
24
+ });
25
+ document.getElementById("status").innerText =
26
+ "📍 Location sent to server";
27
+ },
28
+ () => alert("Location permission denied")
29
+ );
30
+ }
31
+ </script>
32
+
33
+ </body>
34
+ </html>
templates/index.html ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Bus Stop Alert</title>
6
+ <link rel="stylesheet" href="../static/style.css">
7
+ <!-- Leaflet CSS -->
8
+ <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
9
+ </head>
10
+ <body>
11
+ <div class="container">
12
+ <h1>Bus Stop / Destination Alert</h1>
13
+
14
+ <!-- Search Section -->
15
+ <div id="search-section">
16
+ <input type="text" id="destination-input" placeholder="Enter destination">
17
+ <button id="search-btn">Search</button>
18
+ </div>
19
+
20
+ <!-- Map -->
21
+ <div id="map"></div>
22
+
23
+ <!-- Favorites -->
24
+ <div id="favorites-section">
25
+ <h2>Favorites</h2>
26
+ <ul id="favorites-list"></ul>
27
+ </div>
28
+
29
+ <!-- Start Tracking -->
30
+ <button id="start-tracking-btn">Start Tracking</button>
31
+ </div>
32
+
33
+ <!-- Leaflet JS -->
34
+ <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
35
+ <!-- Custom JS -->
36
+ <script src="../static/map.js"></script>
37
+ <!-- Custom JS -->
38
+ <script src="../static/map.js"></script>
39
+
40
+ <!-- Geolocation script -->
41
+ <script>
42
+ navigator.geolocation.getCurrentPosition(function(position) {
43
+ fetch("http://127.0.0.1:8000/location", {
44
+ method: "POST",
45
+ headers: { "Content-Type": "application/json" },
46
+ body: JSON.stringify({
47
+ lat: position.coords.latitude,
48
+ lon: position.coords.longitude
49
+ })
50
+ });
51
+ });
52
+ </script>
53
+ <!-- Custom JS -->
54
+ <script src="../static/map.js"></script>
55
+
56
+ <!-- Geolocation script -->
57
+ <script>
58
+ navigator.geolocation.getCurrentPosition(function(position) {
59
+ fetch("http://127.0.0.1:8000/location", {
60
+ method: "POST",
61
+ headers: { "Content-Type": "application/json" },
62
+ body: JSON.stringify({
63
+ lat: position.coords.latitude,
64
+ lon: position.coords.longitude
65
+ })
66
+ });
67
+ });
68
+ </script>
69
+
70
+ </body>
71
+ </html>
templates/tracking.html ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Tracking Mode</title>
6
+ <link rel="stylesheet" href="../static/style.css">
7
+ <link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
8
+ </head>
9
+ <body>
10
+ <div class="container">
11
+ <h1>Tracking Mode</h1>
12
+
13
+ <!-- Map -->
14
+ <div id="map"></div>
15
+
16
+ <!-- Distance / Time -->
17
+ <div id="distance-display">
18
+ <span id="distance-text">Calculating distance...</span>
19
+ </div>
20
+
21
+ <!-- Alert Banner -->
22
+ <div id="alert-banner" class="hidden">
23
+ <p>You are about 2 minutes away from your destination!</p>
24
+ <button id="arrived-btn">I've arrived</button>
25
+ </div>
26
+ </div>
27
+
28
+ <script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
29
+ <script src="../static/map.js"></script>
30
+ </body>
31
+ </html>