import gradio as gr import folium from folium import plugins import requests import pandas as pd from datetime import datetime import time import branca.colormap as cm import numpy as np import io from PIL import Image import plotly.graph_objects as go from plotly.subplots import make_subplots import threading # OpenSky API URL BASE_URL = "https://opensky-network.org/api" # Aircraft photos API (예시 - 실제 구현시에는 적절한 API로 대체 필요) AIRCRAFT_PHOTOS_API = "https://api.planespotters.net/pub/photos/hex/{icao24}" def get_aircraft_photo(icao24): """Get aircraft photo from Planespotters API""" try: response = requests.get(AIRCRAFT_PHOTOS_API.format(icao24=icao24)) data = response.json() if data.get('photos'): return data['photos'][0]['thumbnail_large']['src'] except: # 기본 항공기 이미지 URL 반환 return "https://example.com/default-aircraft.jpg" def get_states(bounds=None): """Get current aircraft states from OpenSky Network""" params = {} if bounds: params.update({ 'lamin': bounds[0], 'lomin': bounds[1], 'lamax': bounds[2], 'lomax': bounds[3] }) try: response = requests.get(f"{BASE_URL}/states/all", params=params) data = response.json() return data except Exception as e: print(f"Error fetching data: {e}") return None def create_monitoring_dashboard(data): """Create monitoring dashboard using Plotly""" if not data or 'states' not in data: return None states = data['states'] # Create subplots fig = make_subplots( rows=2, cols=2, subplot_titles=('Altitude Distribution', 'Speed Distribution', 'Aircraft by Country', 'Aircraft Categories') ) # Altitude distribution altitudes = [state[7] for state in states if state[7]] fig.add_trace( go.Histogram(x=altitudes, name="Altitude"), row=1, col=1 ) # Speed distribution speeds = [state[9] for state in states if state[9]] fig.add_trace( go.Histogram(x=speeds, name="Speed"), row=1, col=2 ) # Aircraft by country countries = pd.Series([state[2] for state in states if state[2]]).value_counts() fig.add_trace( go.Bar(x=countries.index[:10], y=countries.values[:10], name="Countries"), row=2, col=1 ) # Aircraft categories categories = pd.Series([state[17] for state in states if state[17]]).value_counts() fig.add_trace( go.Pie(labels=categories.index, values=categories.values, name="Categories"), row=2, col=2 ) fig.update_layout( height=800, showlegend=False, template="plotly_dark", paper_bgcolor='rgba(0,0,0,0)', plot_bgcolor='rgba(0,0,0,0)' ) return fig def create_map(region="world"): """Create aircraft tracking map""" bounds = { "world": None, "europe": [35.0, -15.0, 60.0, 40.0], "north_america": [25.0, -130.0, 50.0, -60.0], "asia": [10.0, 60.0, 50.0, 150.0] } data = get_states(bounds.get(region)) if not data or 'states' not in data: return None, None, "Failed to fetch aircraft data" m = folium.Map( location=[30, 0], zoom_start=3, tiles='CartoDB dark_matter' ) heat_data = [] # Add aircraft markers for state in data['states']: if state[6] and state[5]: lat, lon = state[6], state[5] callsign = state[1] if state[1] else 'N/A' altitude = state[7] if state[7] else 'N/A' velocity = state[9] if state[9] else 'N/A' icao24 = state[0] heat_data.append([lat, lon, 1]) # Get aircraft photo photo_url = get_aircraft_photo(icao24) popup_content = f"""

Flight Information

Callsign: {callsign}

ICAO24: {icao24}

Altitude: {altitude}m

Velocity: {velocity}m/s

Origin: {state[2]}

Status: {'On Ground' if state[8] else 'In Air'}

""" folium.Marker( location=[lat, lon], popup=folium.Popup(popup_content, max_width=300), icon=folium.DivIcon( html=f'''
✈️
''', icon_size=(20, 20) ) ).add_to(m) plugins.HeatMap(heat_data, radius=15).add_to(m) folium.LayerControl().add_to(m) # Create monitoring dashboard dashboard = create_monitoring_dashboard(data) # Create statistics total_aircraft = len(data['states']) countries = len(set(state[2] for state in data['states'] if state[2])) avg_altitude = np.mean([state[7] for state in data['states'] if state[7]]) if data['states'] else 0 in_air = sum(1 for state in data['states'] if not state[8]) on_ground = sum(1 for state in data['states'] if state[8]) stats = f""" 📊 Real-time Statistics: • Total Aircraft: {total_aircraft} • Aircraft in Air: {in_air} • Aircraft on Ground: {on_ground} • Countries: {countries} • Average Altitude: {avg_altitude:.0f}m 🔄 Last Updated: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')} """ return m._repr_html_(), dashboard, stats # Custom CSS custom_css = """ .gradio-container { background: linear-gradient(135deg, #1a1a1a, #2d2d2d) !important; color: #ffffff !important; } .gr-button { background: linear-gradient(135deg, #4a90e2, #357abd) !important; border: none !important; color: white !important; } .gr-button:hover { background: linear-gradient(135deg, #357abd, #4a90e2) !important; transform: translateY(-2px); box-shadow: 0 5px 15px rgba(74, 144, 226, 0.4) !important; } .title-text { text-align: center !important; color: #ffffff !important; font-size: 2.5em !important; margin-bottom: 0.5em !important; text-shadow: 2px 2px 4px rgba(0,0,0,0.5) !important; } .dashboard { background: rgba(0, 0, 0, 0.3) !important; border-radius: 10px !important; padding: 20px !important; } """ with gr.Blocks(css=custom_css) as demo: gr.HTML( """
🛩️ Global Aircraft Tracker
""" ) with gr.Row(): with gr.Column(scale=2): region_select = gr.Dropdown( choices=["world", "europe", "north_america", "asia"], value="world", label="Select Region" ) with gr.Column(scale=1): refresh_btn = gr.Button("🔄 Refresh") auto_refresh = gr.Checkbox(label="Auto Refresh", value=False) with gr.Row(): with gr.Column(scale=2): map_html = gr.HTML() with gr.Column(scale=1): stats_text = gr.Textbox(label="Statistics", lines=8) with gr.Row(): dashboard_plot = gr.Plot(label="Monitoring Dashboard") def update_map(region): return create_map(region) def auto_refresh_function(auto_refresh_state): while auto_refresh_state: time.sleep(30) # 30초 대기 map_data, dashboard_data, stats_data = create_map(region_select.value) map_html.update(value=map_data) dashboard_plot.update(value=dashboard_data) stats_text.update(value=stats_data) refresh_btn.click( fn=update_map, inputs=[region_select], outputs=[map_html, dashboard_plot, stats_text] ) region_select.change( fn=update_map, inputs=[region_select], outputs=[map_html, dashboard_plot, stats_text] ) def handle_auto_refresh(auto_refresh_state): if auto_refresh_state: threading.Thread(target=auto_refresh_function, args=(True,), daemon=True).start() auto_refresh.change( fn=handle_auto_refresh, inputs=[auto_refresh] ) # Initial map load map_html, dashboard_plot, stats_text = create_map("world") demo.launch()