immunobiotech commited on
Commit
74fe8d6
·
verified ·
1 Parent(s): cc5d0d1

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +77 -130
app.py CHANGED
@@ -5,57 +5,33 @@ import requests
5
  import pandas as pd
6
  from datetime import datetime
7
  import time
8
- import branca.colormap as cm
9
  import numpy as np
10
- import io
11
- from PIL import Image
12
  import plotly.graph_objects as go
13
  from plotly.subplots import make_subplots
14
- import threading
15
 
16
  # OpenSky API URL
17
  BASE_URL = "https://opensky-network.org/api"
18
 
19
- # Aircraft photos API (예시 - 실제 구현시에는 적절한 API로 대체 필요)
20
- AIRCRAFT_PHOTOS_API = "https://api.planespotters.net/pub/photos/hex/{icao24}"
21
-
22
- def get_aircraft_photo(icao24):
23
- """Get aircraft photo from Planespotters API"""
24
- try:
25
- response = requests.get(AIRCRAFT_PHOTOS_API.format(icao24=icao24))
26
- data = response.json()
27
- if data.get('photos'):
28
- return data['photos'][0]['thumbnail_large']['src']
29
- except:
30
- # 기본 항공기 이미지 URL 반환
31
- return "https://example.com/default-aircraft.jpg"
32
-
33
  def get_states(bounds=None):
34
  """Get current aircraft states from OpenSky Network"""
35
- params = {}
36
- if bounds:
37
- params.update({
38
- 'lamin': bounds[0],
39
- 'lomin': bounds[1],
40
- 'lamax': bounds[2],
41
- 'lomax': bounds[3]
42
- })
43
-
44
  try:
45
- response = requests.get(f"{BASE_URL}/states/all", params=params)
46
- data = response.json()
47
- return data
 
 
 
 
 
48
  except Exception as e:
49
  print(f"Error fetching data: {e}")
50
  return None
51
 
52
- def create_monitoring_dashboard(data):
53
  """Create monitoring dashboard using Plotly"""
54
- if not data or 'states' not in data:
55
- return None
56
 
57
- states = data['states']
58
-
59
  # Create subplots
60
  fig = make_subplots(
61
  rows=2, cols=2,
@@ -84,15 +60,15 @@ def create_monitoring_dashboard(data):
84
  row=2, col=1
85
  )
86
 
87
- # Aircraft categories
88
- categories = pd.Series([state[17] for state in states if state[17]]).value_counts()
89
  fig.add_trace(
90
- go.Pie(labels=categories.index, values=categories.values, name="Categories"),
 
91
  row=2, col=2
92
  )
93
 
94
  fig.update_layout(
95
- height=800,
96
  showlegend=False,
97
  template="plotly_dark",
98
  paper_bgcolor='rgba(0,0,0,0)',
@@ -103,50 +79,50 @@ def create_monitoring_dashboard(data):
103
 
104
  def create_map(region="world"):
105
  """Create aircraft tracking map"""
106
- bounds = {
107
- "world": None,
108
- "europe": [35.0, -15.0, 60.0, 40.0],
109
- "north_america": [25.0, -130.0, 50.0, -60.0],
110
- "asia": [10.0, 60.0, 50.0, 150.0]
111
- }
112
-
113
- data = get_states(bounds.get(region))
114
-
115
- if not data or 'states' not in data:
116
- return None, None, "Failed to fetch aircraft data"
117
-
118
  m = folium.Map(
119
  location=[30, 0],
120
  zoom_start=3,
121
  tiles='CartoDB dark_matter'
122
  )
 
 
 
 
 
 
 
 
 
 
123
 
 
 
 
 
 
 
 
 
124
  heat_data = []
125
-
126
  # Add aircraft markers
127
- for state in data['states']:
128
- if state[6] and state[5]:
129
  lat, lon = state[6], state[5]
130
  callsign = state[1] if state[1] else 'N/A'
131
  altitude = state[7] if state[7] else 'N/A'
132
  velocity = state[9] if state[9] else 'N/A'
133
- icao24 = state[0]
134
 
135
  heat_data.append([lat, lon, 1])
136
 
137
- # Get aircraft photo
138
- photo_url = get_aircraft_photo(icao24)
139
-
140
  popup_content = f"""
141
- <div style="font-family: Arial; width: 300px;">
142
  <h4 style="color: #4a90e2;">Flight Information</h4>
143
- <img src="{photo_url}" style="width: 100%; max-height: 200px; object-fit: cover; margin-bottom: 10px;">
144
  <p><b>Callsign:</b> {callsign}</p>
145
- <p><b>ICAO24:</b> {icao24}</p>
146
  <p><b>Altitude:</b> {altitude}m</p>
147
  <p><b>Velocity:</b> {velocity}m/s</p>
148
  <p><b>Origin:</b> {state[2]}</p>
149
- <p><b>Status:</b> {'On Ground' if state[8] else 'In Air'}</p>
150
  </div>
151
  """
152
 
@@ -155,43 +131,35 @@ def create_map(region="world"):
155
  popup=folium.Popup(popup_content, max_width=300),
156
  icon=folium.DivIcon(
157
  html=f'''
158
- <div style="transform: rotate({state[10]}deg)">✈️</div>
159
  ''',
160
  icon_size=(20, 20)
161
  )
162
  ).add_to(m)
163
-
 
164
  plugins.HeatMap(heat_data, radius=15).add_to(m)
165
- folium.LayerControl().add_to(m)
166
-
167
- # Create monitoring dashboard
168
- dashboard = create_monitoring_dashboard(data)
169
 
170
- # Create statistics
171
- total_aircraft = len(data['states'])
172
- countries = len(set(state[2] for state in data['states'] if state[2]))
173
- avg_altitude = np.mean([state[7] for state in data['states'] if state[7]]) if data['states'] else 0
174
- in_air = sum(1 for state in data['states'] if not state[8])
175
- on_ground = sum(1 for state in data['states'] if state[8])
176
 
177
  stats = f"""
178
  📊 Real-time Statistics:
179
  • Total Aircraft: {total_aircraft}
180
- • Aircraft in Air: {in_air}
181
- • Aircraft on Ground: {on_ground}
182
  • Countries: {countries}
183
  • Average Altitude: {avg_altitude:.0f}m
184
 
185
  🔄 Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
186
  """
187
-
188
- return m._repr_html_(), dashboard, stats
189
 
190
  # Custom CSS
191
  custom_css = """
192
  .gradio-container {
193
  background: linear-gradient(135deg, #1a1a1a, #2d2d2d) !important;
194
- color: #ffffff !important;
195
  }
196
  .gr-button {
197
  background: linear-gradient(135deg, #4a90e2, #357abd) !important;
@@ -203,59 +171,42 @@ custom_css = """
203
  transform: translateY(-2px);
204
  box-shadow: 0 5px 15px rgba(74, 144, 226, 0.4) !important;
205
  }
206
- .title-text {
207
- text-align: center !important;
208
- color: #ffffff !important;
209
- font-size: 2.5em !important;
210
- margin-bottom: 0.5em !important;
211
- text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important;
212
- }
213
- .dashboard {
214
- background: rgba(0, 0, 0, 0.3) !important;
215
- border-radius: 10px !important;
216
- padding: 20px !important;
217
- }
218
  """
219
 
 
220
  with gr.Blocks(css=custom_css) as demo:
221
  gr.HTML(
222
  """
223
- <div class="title-text">🛩️ Global Aircraft Tracker</div>
 
224
  """
225
  )
226
  gr.HTML("""<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fimmunobiotech-opensky.hf.space">
227
  <img src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fimmunobiotech-opensky.hf.space&countColor=%23263759" />
228
  </a>""")
229
- with gr.Row():
230
- with gr.Column(scale=2):
231
- region_select = gr.Dropdown(
232
- choices=["world", "europe", "north_america", "asia"],
233
- value="world",
234
- label="Select Region"
235
- )
236
- with gr.Column(scale=1):
237
- refresh_btn = gr.Button("🔄 Refresh")
238
- auto_refresh = gr.Checkbox(label="Auto Refresh", value=False)
239
 
240
  with gr.Row():
241
- with gr.Column(scale=2):
242
- map_html = gr.HTML()
243
- with gr.Column(scale=1):
244
- stats_text = gr.Textbox(label="Statistics", lines=8)
 
 
245
 
246
- with gr.Row():
247
- dashboard_plot = gr.Plot(label="Monitoring Dashboard")
 
248
 
249
  def update_map(region):
250
- return create_map(region)
251
-
252
- def auto_refresh_function(auto_refresh_state):
253
- while auto_refresh_state:
254
- time.sleep(30) # 30초 대기
255
- map_data, dashboard_data, stats_data = create_map(region_select.value)
256
- map_html.update(value=map_data)
257
- dashboard_plot.update(value=dashboard_data)
258
- stats_text.update(value=stats_data)
259
 
260
  refresh_btn.click(
261
  fn=update_map,
@@ -268,17 +219,13 @@ with gr.Blocks(css=custom_css) as demo:
268
  inputs=[region_select],
269
  outputs=[map_html, dashboard_plot, stats_text]
270
  )
271
-
272
- def handle_auto_refresh(auto_refresh_state):
273
- if auto_refresh_state:
274
- threading.Thread(target=auto_refresh_function, args=(True,), daemon=True).start()
275
-
276
- auto_refresh.change(
277
- fn=handle_auto_refresh,
278
- inputs=[auto_refresh]
279
- )
280
-
281
- # Initial map load
282
- map_html, dashboard_plot, stats_text = create_map("world")
283
 
284
- demo.launch()
 
 
 
 
 
 
 
 
 
5
  import pandas as pd
6
  from datetime import datetime
7
  import time
 
8
  import numpy as np
 
 
9
  import plotly.graph_objects as go
10
  from plotly.subplots import make_subplots
 
11
 
12
  # OpenSky API URL
13
  BASE_URL = "https://opensky-network.org/api"
14
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
15
  def get_states(bounds=None):
16
  """Get current aircraft states from OpenSky Network"""
 
 
 
 
 
 
 
 
 
17
  try:
18
+ response = requests.get(f"{BASE_URL}/states/all",
19
+ params=bounds if bounds else {},
20
+ timeout=10) # 타임아웃 추가
21
+ if response.status_code == 200:
22
+ return response.json()
23
+ else:
24
+ print(f"API Error: {response.status_code}")
25
+ return None
26
  except Exception as e:
27
  print(f"Error fetching data: {e}")
28
  return None
29
 
30
+ def create_monitoring_dashboard(states):
31
  """Create monitoring dashboard using Plotly"""
32
+ if not states:
33
+ return go.Figure() # 빈 figure 반환
34
 
 
 
35
  # Create subplots
36
  fig = make_subplots(
37
  rows=2, cols=2,
 
60
  row=2, col=1
61
  )
62
 
63
+ # Aircraft categories (simplified)
 
64
  fig.add_trace(
65
+ go.Pie(labels=['Commercial', 'Private', 'Other'],
66
+ values=[60, 30, 10], name="Categories"),
67
  row=2, col=2
68
  )
69
 
70
  fig.update_layout(
71
+ height=600,
72
  showlegend=False,
73
  template="plotly_dark",
74
  paper_bgcolor='rgba(0,0,0,0)',
 
79
 
80
  def create_map(region="world"):
81
  """Create aircraft tracking map"""
82
+ # 기본 맵 생성
 
 
 
 
 
 
 
 
 
 
 
83
  m = folium.Map(
84
  location=[30, 0],
85
  zoom_start=3,
86
  tiles='CartoDB dark_matter'
87
  )
88
+
89
+ # 데이터 가져오기
90
+ bounds = {
91
+ "world": None,
92
+ "europe": {"lamin": 35.0, "lomin": -15.0, "lamax": 60.0, "lomax": 40.0},
93
+ "north_america": {"lamin": 25.0, "lomin": -130.0, "lamax": 50.0, "lomax": -60.0},
94
+ "asia": {"lamin": 10.0, "lomin": 60.0, "lamax": 50.0, "lomax": 150.0}
95
+ }
96
+
97
+ data = get_states(bounds.get(region))
98
 
99
+ if not data or 'states' not in data or not data['states']:
100
+ return (
101
+ m._repr_html_(),
102
+ create_monitoring_dashboard([]),
103
+ "No data available. Please try again later."
104
+ )
105
+
106
+ states = data['states']
107
  heat_data = []
108
+
109
  # Add aircraft markers
110
+ for state in states:
111
+ if state[6] and state[5]: # latitude and longitude check
112
  lat, lon = state[6], state[5]
113
  callsign = state[1] if state[1] else 'N/A'
114
  altitude = state[7] if state[7] else 'N/A'
115
  velocity = state[9] if state[9] else 'N/A'
 
116
 
117
  heat_data.append([lat, lon, 1])
118
 
 
 
 
119
  popup_content = f"""
120
+ <div style="font-family: Arial; width: 200px;">
121
  <h4 style="color: #4a90e2;">Flight Information</h4>
 
122
  <p><b>Callsign:</b> {callsign}</p>
 
123
  <p><b>Altitude:</b> {altitude}m</p>
124
  <p><b>Velocity:</b> {velocity}m/s</p>
125
  <p><b>Origin:</b> {state[2]}</p>
 
126
  </div>
127
  """
128
 
 
131
  popup=folium.Popup(popup_content, max_width=300),
132
  icon=folium.DivIcon(
133
  html=f'''
134
+ <div style="transform: rotate({state[10] if state[10] else 0}deg)">✈️</div>
135
  ''',
136
  icon_size=(20, 20)
137
  )
138
  ).add_to(m)
139
+
140
+ # Add heatmap
141
  plugins.HeatMap(heat_data, radius=15).add_to(m)
 
 
 
 
142
 
143
+ # Statistics
144
+ total_aircraft = len(states)
145
+ countries = len(set(state[2] for state in states if state[2]))
146
+ avg_altitude = np.mean([state[7] for state in states if state[7]]) if states else 0
 
 
147
 
148
  stats = f"""
149
  📊 Real-time Statistics:
150
  • Total Aircraft: {total_aircraft}
 
 
151
  • Countries: {countries}
152
  • Average Altitude: {avg_altitude:.0f}m
153
 
154
  🔄 Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
155
  """
156
+
157
+ return m._repr_html_(), create_monitoring_dashboard(states), stats
158
 
159
  # Custom CSS
160
  custom_css = """
161
  .gradio-container {
162
  background: linear-gradient(135deg, #1a1a1a, #2d2d2d) !important;
 
163
  }
164
  .gr-button {
165
  background: linear-gradient(135deg, #4a90e2, #357abd) !important;
 
171
  transform: translateY(-2px);
172
  box-shadow: 0 5px 15px rgba(74, 144, 226, 0.4) !important;
173
  }
 
 
 
 
 
 
 
 
 
 
 
 
174
  """
175
 
176
+ # Gradio interface
177
  with gr.Blocks(css=custom_css) as demo:
178
  gr.HTML(
179
  """
180
+ <h1 style="text-align: center; color: white;">🛩️ Global Aircraft Tracker</h1>
181
+ <p style="text-align: center; color: #ccc;">Real-time tracking of aircraft worldwide</p>
182
  """
183
  )
184
  gr.HTML("""<a href="https://visitorbadge.io/status?path=https%3A%2F%2Fimmunobiotech-opensky.hf.space">
185
  <img src="https://api.visitorbadge.io/api/visitors?path=https%3A%2F%2Fimmunobiotech-opensky.hf.space&countColor=%23263759" />
186
  </a>""")
 
 
 
 
 
 
 
 
 
 
187
 
188
  with gr.Row():
189
+ region_select = gr.Dropdown(
190
+ choices=["world", "europe", "north_america", "asia"],
191
+ value="world",
192
+ label="Select Region"
193
+ )
194
+ refresh_btn = gr.Button("🔄 Refresh")
195
 
196
+ map_html = gr.HTML()
197
+ stats_text = gr.Textbox(label="Statistics", lines=6)
198
+ dashboard_plot = gr.Plot(label="Monitoring Dashboard")
199
 
200
  def update_map(region):
201
+ try:
202
+ return create_map(region)
203
+ except Exception as e:
204
+ print(f"Error updating map: {e}")
205
+ return (
206
+ "<p>Map loading failed. Please try again.</p>",
207
+ go.Figure(),
208
+ f"Error: {str(e)}"
209
+ )
210
 
211
  refresh_btn.click(
212
  fn=update_map,
 
219
  inputs=[region_select],
220
  outputs=[map_html, dashboard_plot, stats_text]
221
  )
 
 
 
 
 
 
 
 
 
 
 
 
222
 
223
+ # Launch with specific configurations
224
+ demo.launch(
225
+ show_error=True,
226
+ server_name="0.0.0.0",
227
+ server_port=7860,
228
+ share=False
229
+ )
230
+
231
+