Spaces:
Configuration error
Configuration error
| import gradio as gr | |
| import folium | |
| import json | |
| import random | |
| from datetime import datetime, timedelta | |
| # ===== بيانات الأحداث ===== | |
| EVENTS = [ | |
| { | |
| "id": 1, "title": "رصد غارة جوية على مواقع في جنوب لبنان", | |
| "type": "strike", "severity": "critical", "category": "غارة جوية", | |
| "lat": 33.27, "lng": 35.20, "region": "middleeast", | |
| "location": "جنوب لبنان", "details": "غارات متعددة على مواقع عسكرية", | |
| "sources": ["Bamqam", "Conflictly"], "minutes_ago": 30 | |
| }, | |
| { | |
| "id": 2, "title": "إطلاق صواريخ باليستية من اليمن باتجاه البحر الأحمر", | |
| "type": "missile", "severity": "critical", "category": "صاروخ باليستي", | |
| "lat": 15.35, "lng": 44.20, "region": "redSea", | |
| "location": "اليمن — البحر الأحمر", "details": "رصد إطلاق صاروخين باليستيين", | |
| "sources": ["WorldMonitor", "PIZZINT"], "minutes_ago": 60 | |
| }, | |
| { | |
| "id": 3, "title": "تحليق طائرة استطلاع أمريكية RQ-4 فوق شرق المتوسط", | |
| "type": "aircraft", "severity": "high", "category": "طائرة استطلاع", | |
| "lat": 34.50, "lng": 33.80, "region": "middleeast", | |
| "location": "شرق المتوسط", "details": "طائرة بدون طيار للاستطلاع على ارتفاع 55,000 قدم", | |
| "sources": ["ADS-B Exchange", "Flightradar24"], "minutes_ago": 120 | |
| }, | |
| { | |
| "id": 4, "title": "تحركات مدرعات روسية قرب الحدود الأوكرانية", | |
| "type": "troops", "severity": "high", "category": "تحرك قوات", | |
| "lat": 50.45, "lng": 36.60, "region": "europe", | |
| "location": "بيلغورود — روسيا", "details": "رصد رتل مدرعات متحرك", | |
| "sources": ["Conflictly", "WorldMonitor"], "minutes_ago": 90 | |
| }, | |
| { | |
| "id": 5, "title": "اعتراض طائرة مسيّرة فوق مضيق هرمز", | |
| "type": "missile", "severity": "high", "category": "اعتراض", | |
| "lat": 26.56, "lng": 56.25, "region": "middleeast", | |
| "location": "مضيق هرمز", "details": "اعتراض ناجح بصاروخ أرض-جو", | |
| "sources": ["Bamqam", "PIZZINT"], "minutes_ago": 150 | |
| }, | |
| { | |
| "id": 6, "title": "قصف مدفعي متبادل على خط التماس في دونباس", | |
| "type": "strike", "severity": "critical", "category": "قصف مدفعي", | |
| "lat": 48.00, "lng": 37.80, "region": "europe", | |
| "location": "دونباس — أوكرانيا", "details": "أكثر من 200 قذيفة خلال 3 ساعات", | |
| "sources": ["Conflictly", "WorldMonitor"], "minutes_ago": 45 | |
| }, | |
| { | |
| "id": 7, "title": "تحليق مقاتلات F-35 فوق العراق", | |
| "type": "aircraft", "severity": "medium", "category": "دورية جوية", | |
| "lat": 33.30, "lng": 44.36, "region": "middleeast", | |
| "location": "أجواء العراق", "details": "دورية جوية روتينية — 4 مقاتلات", | |
| "sources": ["ADS-B Exchange", "Flightradar24"], "minutes_ago": 180 | |
| }, | |
| { | |
| "id": 8, "title": "تعزيزات بحرية أمريكية في البحر الأحمر", | |
| "type": "naval", "severity": "medium", "category": "نشاط بحري", | |
| "lat": 14.80, "lng": 42.50, "region": "redSea", | |
| "location": "البحر الأحمر", "details": "حاملة طائرات ومدمرتان", | |
| "sources": ["WorldMonitor", "Bamqam"], "minutes_ago": 240 | |
| }, | |
| { | |
| "id": 9, "title": "رصد طائرة شحن عسكري C-17 متجهة لقاعدة العديد", | |
| "type": "aircraft", "severity": "low", "category": "شحن عسكري", | |
| "lat": 25.12, "lng": 51.31, "region": "middleeast", | |
| "location": "قطر — العديد", "details": "شحن عسكري لوجستي", | |
| "sources": ["Flightradar24", "ADS-B Exchange"], "minutes_ago": 300 | |
| }, | |
| { | |
| "id": 10, "title": "غارات على مواقع في غزة", | |
| "type": "strike", "severity": "critical", "category": "غارة جوية", | |
| "lat": 31.42, "lng": 34.35, "region": "middleeast", | |
| "location": "قطاع غزة", "details": "غارات مكثفة على عدة أحياء", | |
| "sources": ["Bamqam", "Conflictly", "WorldMonitor"], "minutes_ago": 10 | |
| }, | |
| { | |
| "id": 11, "title": "تحليق طائرة P-8 فوق البحر الأسود", | |
| "type": "aircraft", "severity": "medium", "category": "طائرة استطلاع", | |
| "lat": 43.50, "lng": 34.00, "region": "europe", | |
| "location": "البحر الأسود", "details": "طائرة مراقبة بحرية — استطلاع", | |
| "sources": ["ADS-B Exchange"], "minutes_ago": 360 | |
| }, | |
| { | |
| "id": 12, "title": "إطلاق صواريخ كروز من البحر المتوسط", | |
| "type": "missile", "severity": "critical", "category": "صاروخ كروز", | |
| "lat": 35.00, "lng": 32.00, "region": "middleeast", | |
| "location": "شرق المتوسط", "details": "رصد إطلاق 4 صواريخ كروز", | |
| "sources": ["PIZZINT", "WorldMonitor"], "minutes_ago": 70 | |
| }, | |
| { | |
| "id": 13, "title": "تحرك فرقة مشاة سودانية قرب الفاشر", | |
| "type": "troops", "severity": "high", "category": "تحرك قوات", | |
| "lat": 13.63, "lng": 25.35, "region": "africa", | |
| "location": "الفاشر — السودان", "details": "تعزيزات عسكرية كبيرة", | |
| "sources": ["Conflictly"], "minutes_ago": 200 | |
| }, | |
| { | |
| "id": 14, "title": "طائرة MQ-9 Reaper فوق سوريا", | |
| "type": "aircraft", "severity": "medium", "category": "طائرة مسيّرة", | |
| "lat": 35.20, "lng": 38.90, "region": "middleeast", | |
| "location": "شمال شرق سوريا", "details": "طائرة مسيّرة للمراقبة والاستطلاع", | |
| "sources": ["ADS-B Exchange", "Flightradar24"], "minutes_ago": 270 | |
| }, | |
| { | |
| "id": 15, "title": "انفجارات قرب قاعدة عين الأسد", | |
| "type": "strike", "severity": "high", "category": "قصف صاروخي", | |
| "lat": 33.80, "lng": 43.50, "region": "middleeast", | |
| "location": "غرب العراق", "details": "سقوط صواريخ كاتيوشا", | |
| "sources": ["Bamqam", "PIZZINT"], "minutes_ago": 133 | |
| }, | |
| ] | |
| FLIGHTS = [ | |
| {"callsign": "FORTE12", "type": "استطلاع", "aircraft": "RQ-4 Global Hawk", "alt": "55,000 ft", "speed": "340 kts", "lat": 34.5, "lng": 33.8, "heading": "090°", "origin": "سيغونيلا"}, | |
| {"callsign": "JAKE21", "type": "مقاتلة", "aircraft": "F-35A Lightning", "alt": "35,000 ft", "speed": "480 kts", "lat": 33.3, "lng": 44.4, "heading": "270°", "origin": "العديد"}, | |
| {"callsign": "RCH405", "type": "شحن", "aircraft": "C-17 Globemaster", "alt": "32,000 ft", "speed": "450 kts", "lat": 25.1, "lng": 51.3, "heading": "180°", "origin": "رامشتاين"}, | |
| {"callsign": "REAP01", "type": "مسيّرة", "aircraft": "MQ-9 Reaper", "alt": "25,000 ft", "speed": "200 kts", "lat": 35.2, "lng": 38.9, "heading": "045°", "origin": "الأردن"}, | |
| {"callsign": "NAVY04", "type": "استطلاع", "aircraft": "P-8A Poseidon", "alt": "28,000 ft", "speed": "380 kts", "lat": 43.5, "lng": 34.0, "heading": "315°", "origin": "كريت"}, | |
| {"callsign": "HAWK77", "type": "مقاتلة", "aircraft": "F-15E Strike Eagle", "alt": "38,000 ft", "speed": "520 kts", "lat": 32.0, "lng": 47.0, "heading": "135°", "origin": "الظفرة"}, | |
| ] | |
| # ===== ألوان وأيقونات ===== | |
| TYPE_CONFIG = { | |
| "strike": {"color": "#ef4444", "icon": "💥", "name": "غارة / ضربة"}, | |
| "missile": {"color": "#f97316", "icon": "🚀", "name": "صاروخ"}, | |
| "aircraft": {"color": "#06b6d4", "icon": "✈️", "name": "طائرة"}, | |
| "troops": {"color": "#eab308", "icon": "🎖️", "name": "تحرك قوات"}, | |
| "naval": {"color": "#22c55e", "icon": "🚢", "name": "نشاط بحري"}, | |
| } | |
| SEVERITY_AR = { | |
| "critical": "🔴 حرج", | |
| "high": "🟠 مرتفع", | |
| "medium": "🟡 متوسط", | |
| "low": "🔵 منخفض", | |
| } | |
| REGION_MAP = { | |
| "all": "جميع المناطق", | |
| "middleeast": "الشرق الأوسط", | |
| "europe": "أوروبا الشرقية", | |
| "africa": "شمال أفريقيا", | |
| "redSea": "البحر الأحمر", | |
| "asia": "جنوب آسيا", | |
| } | |
| # ===== دوال المساعدة ===== | |
| def time_ago(minutes): | |
| if minutes < 60: | |
| return f"منذ {minutes} دقيقة" | |
| hours = minutes // 60 | |
| return f"منذ {hours} ساعة" | |
| def remaining_time(minutes): | |
| remaining_mins = max(0, 1440 - minutes) | |
| h = remaining_mins // 60 | |
| m = remaining_mins % 60 | |
| return f"{h} ساعة و {m} دقيقة" | |
| def remaining_pct(minutes): | |
| return max(0, ((1440 - minutes) / 1440) * 100) | |
| # ===== بناء الخريطة ===== | |
| def build_map(region="all", severity=None, event_type=None, search=""): | |
| if severity is None: | |
| severity = ["critical", "high", "medium", "low"] | |
| if event_type is None: | |
| event_type = ["strike", "missile", "aircraft", "troops", "naval"] | |
| m = folium.Map( | |
| location=[30, 40], | |
| zoom_start=4, | |
| tiles=None, | |
| control_scale=True, | |
| ) | |
| folium.TileLayer( | |
| tiles="https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png", | |
| attr="CartoDB Dark", | |
| name="خريطة مظلمة", | |
| control=False, | |
| ).add_to(m) | |
| filtered = EVENTS | |
| if region != "all": | |
| filtered = [e for e in filtered if e["region"] == region] | |
| sev_map = {"🔴 حرج": "critical", "🟠 مرتفع": "high", "🟡 متوسط": "medium", "🔵 منخفض": "low"} | |
| active_sevs = [sev_map.get(s, s) for s in severity] | |
| filtered = [e for e in filtered if e["severity"] in active_sevs] | |
| type_map = {"💥 غارات": "strike", "🚀 صواريخ": "missile", "✈️ طيران": "aircraft", "🎖️ قوات": "troops", "🚢 بحري": "naval"} | |
| active_types = [type_map.get(t, t) for t in event_type] | |
| filtered = [e for e in filtered if e["type"] in active_types] | |
| if search: | |
| filtered = [e for e in filtered if search in e["title"] or search in e["location"]] | |
| for ev in filtered: | |
| cfg = TYPE_CONFIG.get(ev["type"], {"color": "#0ea5e9", "icon": "📍"}) | |
| color = cfg["color"] | |
| icon_char = cfg["icon"] | |
| popup_html = f""" | |
| <div style="direction:rtl;font-family:Arial,sans-serif;min-width:220px;padding:4px;"> | |
| <h4 style="margin:0 0 6px;color:{color};font-size:14px;">{icon_char} {ev['title']}</h4> | |
| <p style="margin:2px 0;font-size:12px;">📍 <b>{ev['location']}</b></p> | |
| <p style="margin:2px 0;font-size:12px;">📋 {ev['details']}</p> | |
| <p style="margin:2px 0;font-size:12px;">🕐 {time_ago(ev['minutes_ago'])}</p> | |
| <p style="margin:2px 0;font-size:12px;">⏱️ متبقي: {remaining_time(ev['minutes_ago'])}</p> | |
| <p style="margin:2px 0;font-size:12px;">📡 {' • '.join(ev['sources'])}</p> | |
| <div style="margin-top:6px;height:4px;background:#333;border-radius:2px;"> | |
| <div style="height:100%;width:{remaining_pct(ev['minutes_ago'])}%;background:{color};border-radius:2px;"></div> | |
| </div> | |
| </div> | |
| """ | |
| icon_html = f""" | |
| <div style=" | |
| width:28px;height:28px;border-radius:50%; | |
| background:radial-gradient(circle,{color}55,{color}20); | |
| border:2px solid {color}; | |
| display:flex;align-items:center;justify-content:center; | |
| font-size:14px; | |
| box-shadow:0 0 12px {color}80; | |
| ">{icon_char}</div> | |
| """ | |
| folium.Marker( | |
| location=[ev["lat"], ev["lng"]], | |
| popup=folium.Popup(popup_html, max_width=300), | |
| icon=folium.DivIcon( | |
| html=icon_html, | |
| icon_size=(28, 28), | |
| icon_anchor=(14, 14), | |
| ), | |
| ).add_to(m) | |
| folium.CircleMarker( | |
| location=[ev["lat"], ev["lng"]], | |
| radius=18, | |
| color=color, | |
| fill=True, | |
| fill_color=color, | |
| fill_opacity=0.08, | |
| weight=1, | |
| opacity=0.3, | |
| ).add_to(m) | |
| for fl in FLIGHTS: | |
| fl_popup = f""" | |
| <div style="direction:rtl;font-family:Arial,sans-serif;min-width:180px;"> | |
| <h4 style="margin:0 0 4px;color:#06b6d4;">{fl['callsign']}</h4> | |
| <p style="margin:2px 0;font-size:12px;">🛩️ {fl['aircraft']}</p> | |
| <p style="margin:2px 0;font-size:12px;">📏 الارتفاع: {fl['alt']}</p> | |
| <p style="margin:2px 0;font-size:12px;">⚡ السرعة: {fl['speed']}</p> | |
| <p style="margin:2px 0;font-size:12px;">🧭 الاتجاه: {fl['heading']}</p> | |
| <p style="margin:2px 0;font-size:12px;">🏠 القاعدة: {fl['origin']}</p> | |
| <p style="margin:2px 0;font-size:12px;">📋 النوع: {fl['type']}</p> | |
| </div> | |
| """ | |
| folium.Marker( | |
| location=[fl["lat"], fl["lng"]], | |
| popup=folium.Popup(fl_popup, max_width=250), | |
| icon=folium.DivIcon( | |
| html=f'<div style="font-size:22px;filter:drop-shadow(0 0 6px #06b6d4);">✈️</div>', | |
| icon_size=(24, 24), | |
| icon_anchor=(12, 12), | |
| ), | |
| ).add_to(m) | |
| legend_html = """ | |
| <div style=" | |
| position:fixed;bottom:30px;right:30px;z-index:9999; | |
| background:rgba(15,20,30,0.92);color:#e2e8f0; | |
| padding:14px 18px;border-radius:10px;font-size:12px; | |
| border:1px solid #2a3a4e;font-family:Arial,sans-serif; | |
| direction:rtl;backdrop-filter:blur(8px); | |
| box-shadow:0 4px 20px rgba(0,0,0,0.4); | |
| "> | |
| <div style="font-weight:bold;margin-bottom:8px;font-size:13px;">🗺️ دليل الرموز</div> | |
| <div style="display:flex;align-items:center;gap:8px;margin:4px 0;"><span style="width:10px;height:10px;border-radius:50%;background:#ef4444;display:inline-block;"></span> غارة / ضربة</div> | |
| <div style="display:flex;align-items:center;gap:8px;margin:4px 0;"><span style="width:10px;height:10px;border-radius:50%;background:#f97316;display:inline-block;"></span> صاروخ</div> | |
| <div style="display:flex;align-items:center;gap:8px;margin:4px 0;"><span style="width:10px;height:10px;border-radius:50%;background:#06b6d4;display:inline-block;"></span> طائرة</div> | |
| <div style="display:flex;align-items:center;gap:8px;margin:4px 0;"><span style="width:10px;height:10px;border-radius:50%;background:#eab308;display:inline-block;"></span> تحرك قوات</div> | |
| <div style="display:flex;align-items:center;gap:8px;margin:4px 0;"><span style="width:10px;height:10px;border-radius:50%;background:#22c55e;display:inline-block;"></span> نشاط بحري</div> | |
| <div style="display:flex;align-items:center;gap:8px;margin:4px 0;"><span style="font-size:14px;">✈️</span> طائرات مراقَبة</div> | |
| </div> | |
| """ | |
| m.get_root().html.add_child(folium.Element(legend_html)) | |
| return m._repr_html_() | |
| # ===== بناء جدول الأحداث ===== | |
| def build_events_table(region="all", severity=None, event_type=None, search=""): | |
| if severity is None: | |
| severity = ["🔴 حرج", "🟠 مرتفع", "🟡 متوسط", "🔵 منخفض"] | |
| if event_type is None: | |
| event_type = ["💥 غارات", "🚀 صواريخ", "✈️ طيران", "🎖️ قوات", "🚢 بحري"] | |
| sev_map = {"🔴 حرج": "critical", "🟠 مرتفع": "high", "🟡 متوسط": "medium", "🔵 منخفض": "low"} | |
| type_map = {"💥 غارات": "strike", "🚀 صواريخ": "missile", "✈️ طيران": "aircraft", "🎖️ قوات": "troops", "🚢 بحري": "naval"} | |
| filtered = EVENTS | |
| if region != "all" and region != "جميع المناطق": | |
| region_key = {v: k for k, v in REGION_MAP.items()}.get(region, region) | |
| filtered = [e for e in filtered if e["region"] == region_key] | |
| active_sevs = [sev_map.get(s, s) for s in severity] | |
| filtered = [e for e in filtered if e["severity"] in active_sevs] | |
| active_types = [type_map.get(t, t) for t in event_type] | |
| filtered = [e for e in filtered if e["type"] in active_types] | |
| if search: | |
| filtered = [e for e in filtered if search in e["title"] or search in e["location"]] | |
| filtered.sort(key=lambda x: x["minutes_ago"]) | |
| sev_colors = {"critical": "#ef4444", "high": "#f97316", "medium": "#eab308", "low": "#0ea5e9"} | |
| sev_names = {"critical": "حرج", "high": "مرتفع", "medium": "متوسط", "low": "منخفض"} | |
| cards_html = "" | |
| for ev in filtered: | |
| cfg = TYPE_CONFIG.get(ev["type"], {"color": "#0ea5e9", "icon": "📍", "name": "—"}) | |
| sc = sev_colors[ev["severity"]] | |
| pct = remaining_pct(ev["minutes_ago"]) | |
| cards_html += f""" | |
| <div style=" | |
| background:linear-gradient(135deg,#1a2332,#1f2937); | |
| border:1px solid #2a3a4e;border-right:3px solid {sc}; | |
| border-radius:10px;padding:14px 16px;margin-bottom:8px; | |
| transition:all 0.2s; | |
| "> | |
| <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;"> | |
| <span style="background:{sc}20;color:{sc};padding:2px 10px;border-radius:4px;font-size:11px;font-weight:bold;"> | |
| {sev_names[ev['severity']]} | |
| </span> | |
| <span style="font-size:11px;color:#64748b;">{cfg['icon']} {ev['category']}</span> | |
| </div> | |
| <div style="font-size:14px;font-weight:bold;margin-bottom:8px;color:#e2e8f0;line-height:1.6;"> | |
| {ev['title']} | |
| </div> | |
| <div style="display:flex;gap:16px;font-size:11px;color:#94a3b8;margin-bottom:8px;"> | |
| <span>📍 {ev['location']}</span> | |
| <span>🕐 {time_ago(ev['minutes_ago'])}</span> | |
| </div> | |
| <div style="display:flex;gap:4px;margin-bottom:8px;"> | |
| {''.join(f'<span style="font-size:10px;padding:2px 8px;border-radius:4px;background:rgba(6,182,212,0.1);color:#06b6d4;border:1px solid rgba(6,182,212,0.2);">{s}</span>' for s in ev['sources'])} | |
| </div> | |
| <div style="display:flex;align-items:center;gap:8px;font-size:10px;color:#f97316;padding-top:8px;border-top:1px solid #2a3a4e;"> | |
| <span>⏱️ متبقي: {remaining_time(ev['minutes_ago'])}</span> | |
| <div style="flex:1;height:3px;background:#2a3a4e;border-radius:2px;"> | |
| <div style="height:100%;width:{pct}%;background:#f97316;border-radius:2px;"></div> | |
| </div> | |
| </div> | |
| </div> | |
| """ | |
| return cards_html if cards_html else '<div style="text-align:center;padding:40px;color:#64748b;">لا توجد نتائج مطابقة للفلاتر المحددة</div>' | |
| # ===== بناء قائمة الطيران ===== | |
| def build_flights_html(): | |
| type_colors = {"استطلاع": "#a855f7", "مقاتلة": "#ef4444", "شحن": "#22c55e", "مسيّرة": "#f97316"} | |
| html = "" | |
| for fl in FLIGHTS: | |
| tc = type_colors.get(fl["type"], "#06b6d4") | |
| html += f""" | |
| <div style=" | |
| background:linear-gradient(135deg,#1a2332,#1f2937); | |
| border:1px solid #2a3a4e;border-radius:10px; | |
| padding:14px 16px;margin-bottom:8px; | |
| "> | |
| <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;"> | |
| <span style="font-size:16px;font-weight:bold;color:#06b6d4;direction:ltr;">{fl['callsign']}</span> | |
| <span style="background:{tc}20;color:{tc};padding:2px 10px;border-radius:4px;font-size:11px;font-weight:bold;">{fl['type']}</span> | |
| </div> | |
| <div style="display:grid;grid-template-columns:1fr 1fr;gap:6px;font-size:12px;"> | |
| <div style="display:flex;justify-content:space-between;"><span style="color:#64748b;">الطائرة</span><span style="color:#e2e8f0;font-weight:600;">{fl['aircraft']}</span></div> | |
| <div style="display:flex;justify-content:space-between;"><span style="color:#64748b;">الارتفاع</span><span style="color:#e2e8f0;font-weight:600;direction:ltr;">{fl['alt']}</span></div> | |
| <div style="display:flex;justify-content:space-between;"><span style="color:#64748b;">السرعة</span><span style="color:#e2e8f0;font-weight:600;direction:ltr;">{fl['speed']}</span></div> | |
| <div style="display:flex;justify-content:space-between;"><span style="color:#64748b;">الاتجاه</span><span style="color:#e2e8f0;font-weight:600;direction:ltr;">{fl['heading']}</span></div> | |
| <div style="display:flex;justify-content:space-between;grid-column:span 2;"><span style="color:#64748b;">القاعدة</span><span style="color:#e2e8f0;font-weight:600;">{fl['origin']}</span></div> | |
| </div> | |
| </div> | |
| """ | |
| return html | |
| # ===== بناء المصادر ===== | |
| def build_sources_html(): | |
| sources = [ | |
| {"name": "Bamqam", "url": "https://bamqam.com", "status": "متصل", "color": "#22c55e", "desc": "منصة رصد الأحداث العسكرية والنزاعات", "events": 8}, | |
| {"name": "WorldMonitor", "url": "https://worldmonitor.app", "status": "متصل", "color": "#22c55e", "desc": "مراقب النزاعات العالمية المباشر", "events": 6}, | |
| {"name": "Conflictly", "url": "https://conflictly.app", "status": "متصل", "color": "#22c55e", "desc": "تتبع وتحليل النزاعات المسلحة", "events": 7}, | |
| {"name": "PIZZINT", "url": "https://pizzint.watch", "status": "جزئي", "color": "#eab308", "desc": "استخبارات مفتوحة المصدر OSINT", "events": 4}, | |
| {"name": "ADS-B Exchange", "url": "https://globe.adsbexchange.com", "status": "متصل", "color": "#22c55e", "desc": "تتبع حركة الطيران بدون فلاتر", "events": 12}, | |
| {"name": "Flightradar24", "url": "https://flightradar24.com", "status": "متصل", "color": "#22c55e", "desc": "رادار الطيران العالمي", "events": 9}, | |
| ] | |
| html = "" | |
| for s in sources: | |
| html += f""" | |
| <div style=" | |
| background:linear-gradient(135deg,#1a2332,#1f2937); | |
| border:1px solid #2a3a4e;border-radius:10px; | |
| padding:14px 16px;margin-bottom:8px; | |
| "> | |
| <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:8px;"> | |
| <span style="font-size:14px;font-weight:bold;color:#e2e8f0;">{s['name']}</span> | |
| <span style="display:flex;align-items:center;gap:4px;font-size:11px;color:{s['color']};"> | |
| <span style="width:7px;height:7px;border-radius:50%;background:{s['color']};display:inline-block;"></span> | |
| {s['status']} | |
| </span> | |
| </div> | |
| <div style="font-size:11px;color:#94a3b8;margin-bottom:6px;">{s['desc']}</div> | |
| <div style="display:flex;justify-content:space-between;font-size:10px;color:#64748b;"> | |
| <span>🔗 <a href="{s['url']}" target="_blank" style="color:#06b6d4;text-decoration:none;">{s['url'].replace('https://','')}</a></span> | |
| <span>📊 {s['events']} حدث</span> | |
| </div> | |
| </div> | |
| """ | |
| return html | |
| # ===== بناء الإحصائيات ===== | |
| def build_stats_html(): | |
| total = len(EVENTS) | |
| strikes = len([e for e in EVENTS if e["type"] == "strike"]) | |
| missiles = len([e for e in EVENTS if e["type"] == "missile"]) | |
| aircraft = len([e for e in EVENTS if e["type"] == "aircraft"]) | |
| troops = len([e for e in EVENTS if e["type"] == "troops"]) | |
| naval = len([e for e in EVENTS if e["type"] == "naval"]) | |
| critical = len([e for e in EVENTS if e["severity"] == "critical"]) | |
| now = datetime.now().strftime("%Y/%m/%d — %H:%M:%S") | |
| return f""" | |
| <div style="display:flex;flex-wrap:wrap;gap:8px;direction:rtl;"> | |
| <div style="flex:1;min-width:130px;background:linear-gradient(135deg,#1a2332,#1f2937);border:1px solid #2a3a4e;border-radius:10px;padding:14px;text-align:center;"> | |
| <div style="font-size:28px;font-weight:900;color:#ef4444;">{total}</div> | |
| <div style="font-size:11px;color:#94a3b8;">إجمالي الأحداث</div> | |
| </div> | |
| <div style="flex:1;min-width:130px;background:linear-gradient(135deg,#1a2332,#1f2937);border:1px solid #2a3a4e;border-radius:10px;padding:14px;text-align:center;"> | |
| <div style="font-size:28px;font-weight:900;color:#f97316;">{strikes}</div> | |
| <div style="font-size:11px;color:#94a3b8;">💥 غارات / ضربات</div> | |
| </div> | |
| <div style="flex:1;min-width:130px;background:linear-gradient(135deg,#1a2332,#1f2937);border:1px solid #2a3a4e;border-radius:10px;padding:14px;text-align:center;"> | |
| <div style="font-size:28px;font-weight:900;color:#a855f7;">{missiles}</div> | |
| <div style="font-size:11px;color:#94a3b8;">🚀 صواريخ</div> | |
| </div> | |
| <div style="flex:1;min-width:130px;background:linear-gradient(135deg,#1a2332,#1f2937);border:1px solid #2a3a4e;border-radius:10px;padding:14px;text-align:center;"> | |
| <div style="font-size:28px;font-weight:900;color:#06b6d4;">{aircraft}</div> | |
| <div style="font-size:11px;color:#94a3b8;">✈️ طائرات</div> | |
| </div> | |
| <div style="flex:1;min-width:130px;background:linear-gradient(135deg,#1a2332,#1f2937);border:1px solid #2a3a4e;border-radius:10px;padding:14px;text-align:center;"> | |
| <div style="font-size:28px;font-weight:900;color:#eab308;">{troops}</div> | |
| <div style="font-size:11px;color:#94a3b8;">🎖️ قوات</div> | |
| </div> | |
| <div style="flex:1;min-width:130px;background:linear-gradient(135deg,#1a2332,#1f2937);border:1px solid #2a3a4e;border-radius:10px;padding:14px;text-align:center;"> | |
| <div style="font-size:28px;font-weight:900;color:#22c55e;">{naval}</div> | |
| <div style="font-size:11px;color:#94a3b8;">🚢 بحري</div> | |
| </div> | |
| </div> | |
| <div style="margin-top:10px;text-align:center;font-size:11px;color:#64748b;"> | |
| 🕐 آخر تحديث: {now} | 🔴 أحداث حرجة: {critical} | ⏱️ الأحداث تنتهي بعد 24 ساعة | |
| </div> | |
| """ | |
| # ===== الدالة الرئيسية للتحديث ===== | |
| def update_dashboard(region, severity, event_type, search): | |
| map_html = build_map(region, severity, event_type, search) | |
| events_html = build_events_table(region, severity, event_type, search) | |
| stats_html = build_stats_html() | |
| return map_html, events_html, stats_html | |
| def update_all(region, severity, event_type, search): | |
| map_h, events_h, stats_h = update_dashboard(region, severity, event_type, search) | |
| return stats_h, map_h, events_h | |
| # ===== CSS ===== | |
| CUSTOM_CSS = """ | |
| @import url('https://fonts.googleapis.com/css2?family=Cairo:wght@300;400;600;700;800;900&display=swap'); | |
| * { font-family: 'Cairo', sans-serif !important; } | |
| .gradio-container { | |
| max-width: 100% !important; | |
| background: #0a0e17 !important; | |
| color: #e2e8f0 !important; | |
| } | |
| .dark { background: #0a0e17 !important; } | |
| #header-bar { | |
| background: linear-gradient(135deg, #0f172a, #1e293b) !important; | |
| border: 1px solid #2a3a4e !important; | |
| border-radius: 12px !important; | |
| padding: 16px 24px !important; | |
| margin-bottom: 8px !important; | |
| } | |
| .tab-nav button { | |
| background: #1a2332 !important; | |
| color: #94a3b8 !important; | |
| border: 1px solid #2a3a4e !important; | |
| border-radius: 8px !important; | |
| font-weight: 700 !important; | |
| font-size: 13px !important; | |
| } | |
| .tab-nav button.selected { | |
| background: rgba(14,165,233,0.15) !important; | |
| color: #0ea5e9 !important; | |
| border-color: #0ea5e9 !important; | |
| } | |
| .block { background: transparent !important; border: none !important; } | |
| label { color: #94a3b8 !important; font-weight: 600 !important; } | |
| input, select, textarea, .wrap { | |
| background: #1a2332 !important; | |
| border: 1px solid #2a3a4e !important; | |
| color: #e2e8f0 !important; | |
| border-radius: 8px !important; | |
| } | |
| .checkbox-group label { color: #e2e8f0 !important; } | |
| button.primary { | |
| background: linear-gradient(135deg, #0ea5e9, #06b6d4) !important; | |
| border: none !important; | |
| font-weight: 700 !important; | |
| border-radius: 8px !important; | |
| } | |
| .ticker-bar { | |
| background: rgba(239,68,68,0.08); | |
| border: 1px solid rgba(239,68,68,0.2); | |
| border-radius: 8px; | |
| padding: 8px 16px; | |
| text-align: center; | |
| font-size: 13px; | |
| color: #ef4444; | |
| font-weight: 700; | |
| overflow: hidden; | |
| white-space: nowrap; | |
| margin-bottom: 8px; | |
| } | |
| footer { display: none !important; } | |
| """ | |
| # ===== بناء التطبيق ===== | |
| with gr.Blocks( | |
| css=CUSTOM_CSS, | |
| title="مركز رصد النزاعات والتطورات العسكرية", | |
| theme=gr.themes.Base( | |
| primary_hue="sky", | |
| neutral_hue="slate", | |
| ), | |
| ) as app: | |
| # ===== الرأس ===== | |
| gr.HTML(""" | |
| <div id="header-bar" style=" | |
| background:linear-gradient(135deg,#0f172a,#1e293b); | |
| border:1px solid #2a3a4e;border-radius:12px; | |
| padding:16px 24px;margin-bottom:8px; | |
| display:flex;justify-content:space-between;align-items:center; | |
| direction:rtl; | |
| "> | |
| <div style="display:flex;align-items:center;gap:14px;"> | |
| <div style=" | |
| width:48px;height:48px;border-radius:12px; | |
| background:linear-gradient(135deg,#0ea5e9,#06b6d4); | |
| display:flex;align-items:center;justify-content:center; | |
| font-size:24px; | |
| ">🛡️</div> | |
| <div> | |
| <h1 style="margin:0;font-size:22px;font-weight:900; | |
| background:linear-gradient(135deg,#e2e8f0,#0ea5e9); | |
| -webkit-background-clip:text;-webkit-text-fill-color:transparent;"> | |
| مركز رصد النزاعات والتطورات العسكرية | |
| </h1> | |
| <p style="margin:0;font-size:12px;color:#64748b;">نظام المراقبة والإنذار المبكر — تحديث تلقائي — بيانات من 6 مصادر موثوقة</p> | |
| </div> | |
| </div> | |
| <div style="display:flex;align-items:center;gap:16px;"> | |
| <div style=" | |
| display:flex;align-items:center;gap:8px; | |
| background:rgba(239,68,68,0.1);border:1px solid rgba(239,68,68,0.3); | |
| padding:6px 16px;border-radius:20px;font-size:13px; | |
| color:#ef4444;font-weight:700; | |
| "> | |
| <span style="width:8px;height:8px;background:#ef4444;border-radius:50%;display:inline-block;animation:pulse 1.5s infinite;"></span> | |
| بث مباشر | |
| </div> | |
| </div> | |
| </div> | |
| <style>@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.4}}</style> | |
| """) | |
| # شريط الأخبار العاجلة | |
| gr.HTML(""" | |
| <div class="ticker-bar"> | |
| 🔴 عاجل: رصد تحركات عسكرية غير اعتيادية | | |
| ⚠️ تنبيه: طائرة استطلاع فوق مناطق النزاع | | |
| 🔴 تقارير عن إطلاق صواريخ باليستية | | |
| 📡 رصد: تغيير في أنماط الطيران العسكري فوق البحر الأحمر | |
| </div> | |
| """) | |
| # الإحصائيات | |
| stats_display = gr.HTML(value=build_stats_html()) | |
| # ===== الفلاتر ===== | |
| with gr.Row(): | |
| with gr.Column(scale=1): | |
| region_dd = gr.Dropdown( | |
| choices=list(REGION_MAP.values()), | |
| value="جميع المناطق", | |
| label="🌍 المنطقة", | |
| ) | |
| with gr.Column(scale=2): | |
| severity_cb = gr.CheckboxGroup( | |
| choices=["🔴 حرج", "🟠 مرتفع", "🟡 متوسط", "🔵 منخفض"], | |
| value=["🔴 حرج", "🟠 مرتفع", "🟡 متوسط", "🔵 منخفض"], | |
| label="⚡ مستوى الخطورة", | |
| ) | |
| with gr.Column(scale=2): | |
| type_cb = gr.CheckboxGroup( | |
| choices=["💥 غارات", "🚀 صواريخ", "✈️ طيران", "🎖️ قوات", "🚢 بحري"], | |
| value=["💥 غارات", "🚀 صواريخ", "✈️ طيران", "🎖️ قوات", "🚢 بحري"], | |
| label="📋 نوع الحدث", | |
| ) | |
| with gr.Column(scale=1): | |
| search_box = gr.Textbox(label="🔍 بحث", placeholder="ابحث في الأحداث...") | |
| apply_btn = gr.Button("🔄 تطبيق الفلاتر وتحديث", variant="primary", size="lg") | |
| # ===== المحتوى الرئيسي ===== | |
| with gr.Tabs(): | |
| # === تبويب الخريطة والأحداث === | |
| with gr.Tab("🗺️ الخريطة والأحداث"): | |
| with gr.Row(): | |
| with gr.Column(scale=3): | |
| map_display = gr.HTML( | |
| value=build_map(), | |
| label="الخريطة", | |
| ) | |
| with gr.Column(scale=1): | |
| events_display = gr.HTML( | |
| value=build_events_table(), | |
| label="آخر الأحداث", | |
| ) | |
| # === تبويب الطيران === | |
| with gr.Tab("✈️ حركة الطيران"): | |
| gr.HTML(""" | |
| <div style=" | |
| background:linear-gradient(135deg,#0f172a,#1e293b); | |
| border:1px solid #2a3a4e;border-radius:10px;padding:14px;margin-bottom:10px; | |
| text-align:center;direction:rtl; | |
| "> | |
| <span style="font-size:14px;font-weight:700;color:#06b6d4;">📡 الطائرات المراقَبة حالياً</span> | |
| <span style="font-size:12px;color:#94a3b8;margin-right:12px;"> | |
| المصادر: ADS-B Exchange • Flightradar24 | |
| </span> | |
| </div> | |
| """) | |
| flights_display = gr.HTML(value=build_flights_html()) | |
| # === تبويب المصادر === | |
| with gr.Tab("📡 المصادر"): | |
| gr.HTML(""" | |
| <div style=" | |
| background:linear-gradient(135deg,#0f172a,#1e293b); | |
| border:1px solid #2a3a4e;border-radius:10px;padding:14px;margin-bottom:10px; | |
| text-align:center;direction:rtl; | |
| "> | |
| <span style="font-size:14px;font-weight:700;color:#0ea5e9;">🔗 مصادر البيانات المتصلة</span> | |
| <span style="font-size:12px;color:#94a3b8;margin-right:12px;"> | |
| 6 مصادر — 5 متصل — 1 جزئي | |
| </span> | |
| </div> | |
| """) | |
| sources_display = gr.HTML(value=build_sources_html()) | |
| # === تبويب حول === | |
| with gr.Tab("ℹ️ حول النظام"): | |
| gr.HTML(""" | |
| <div style="direction:rtl;padding:20px;max-width:700px;margin:0 auto;"> | |
| <div style="background:linear-gradient(135deg,#0f172a,#1e293b);border:1px solid #2a3a4e;border-radius:12px;padding:24px;"> | |
| <h2 style="color:#0ea5e9;margin-top:0;">🛡️ مركز رصد النزاعات والتطورات العسكرية</h2> | |
| <p style="color:#94a3b8;line-height:1.8;font-size:14px;"> | |
| نظام متكامل لمراقبة وتتبع التطورات العسكرية والنزاعات حول العالم. | |
| يعتمد النظام على جمع البيانات من مصادر متعددة وموثوقة وعرضها | |
| بشكل تفاعلي على خريطة مع تنبيهات فورية. | |
| </p> | |
| <h3 style="color:#e2e8f0;margin-top:16px;">📋 المزايا الرئيسية</h3> | |
| <ul style="color:#94a3b8;line-height:2;font-size:13px;"> | |
| <li>خريطة تفاعلية مظلمة بنمط تكتيكي عسكري</li> | |
| <li>تصنيف الأحداث: غارات، صواريخ، طيران، قوات، نشاط بحري</li> | |
| <li>مستويات خطورة: حرج، مرتفع، متوسط، منخفض</li> | |
| <li>مؤقت 24 ساعة لكل حدث — ينتهي تلقائياً</li> | |
| <li>ربط كل خبر بموقعه الجغرافي على الخريطة</li> | |
| <li>تتبع حركة الطيران العسكري والاستطلاعي</li> | |
| <li>فلاتر متقدمة: منطقة، خطورة، نوع، بحث نصي</li> | |
| </ul> | |
| <h3 style="color:#e2e8f0;margin-top:16px;">📡 المصادر</h3> | |
| <ul style="color:#94a3b8;line-height:2;font-size:13px;"> | |
| <li><a href="https://bamqam.com" target="_blank" style="color:#06b6d4;">Bamqam</a> — رصد الأحداث العسكرية</li> | |
| <li><a href="https://worldmonitor.app" target="_blank" style="color:#06b6d4;">WorldMonitor</a> — مراقب النزاعات العالمية</li> | |
| <li><a href="https://conflictly.app" target="_blank" style="color:#06b6d4;">Conflictly</a> — تتبع النزاعات المسلحة</li> | |
| <li><a href="https://pizzint.watch" target="_blank" style="color:#06b6d4;">PIZZINT</a> — استخبارات مفتوحة المصدر</li> | |
| <li><a href="https://globe.adsbexchange.com" target="_blank" style="color:#06b6d4;">ADS-B Exchange</a> — تتبع الطيران</li> | |
| <li><a href="https://flightradar24.com" target="_blank" style="color:#06b6d4;">Flightradar24</a> — رادار الطيران</li> | |
| </ul> | |
| </div> | |
| </div> | |
| """) | |
| # ===== الشريط السفلي ===== | |
| gr.HTML(""" | |
| <div style=" | |
| background:rgba(15,23,42,0.9);border:1px solid #2a3a4e; | |
| border-radius:10px;padding:10px 20px;margin-top:8px; | |
| display:flex;justify-content:space-between;align-items:center; | |
| font-size:11px;color:#64748b;direction:rtl; | |
| "> | |
| <div style="display:flex;gap:12px;align-items:center;"> | |
| <span>المصادر:</span> | |
| <span style="display:flex;align-items:center;gap:3px;"><span style="width:6px;height:6px;border-radius:50%;background:#22c55e;display:inline-block;"></span> Bamqam</span> | |
| <span style="display:flex;align-items:center;gap:3px;"><span style="width:6px;height:6px;border-radius:50%;background:#22c55e;display:inline-block;"></span> WorldMonitor</span> | |
| <span style="display:flex;align-items:center;gap:3px;"><span style="width:6px;height:6px;border-radius:50%;background:#22c55e;display:inline-block;"></span> Conflictly</span> | |
| <span style="display:flex;align-items:center;gap:3px;"><span style="width:6px;height:6px;border-radius:50%;background:#eab308;display:inline-block;"></span> PIZZINT</span> | |
| <span style="display:flex;align-items:center;gap:3px;"><span style="width:6px;height:6px;border-radius:50%;background:#22c55e;display:inline-block;"></span> ADS-B</span> | |
| <span style="display:flex;align-items:center;gap:3px;"><span style="width:6px;height:6px;border-radius:50%;background:#22c55e;display:inline-block;"></span> FR24</span> | |
| </div> | |
| <div> | |
| ⏱️ الأحداث تنتهي بعد 24 ساعة | 🛡️ مركز رصد النزاعات v1.0 | |
| </div> | |
| </div> | |
| """) | |
| # ===== الأحداث ===== | |
| apply_btn.click( | |
| fn=update_all, | |
| inputs=[region_dd, severity_cb, type_cb, search_box], | |
| outputs=[stats_display, map_display, events_display], | |
| ) | |
| for inp in [region_dd, severity_cb, type_cb]: | |
| inp.change( | |
| fn=update_all, | |
| inputs=[region_dd, severity_cb, type_cb, search_box], | |
| outputs=[stats_display, map_display, events_display], | |
| ) | |
| search_box.submit( | |
| fn=update_all, | |
| inputs=[region_dd, severity_cb, type_cb, search_box], | |
| outputs=[stats_display, map_display, events_display], | |
| ) | |
| # ===== التشغيل ===== | |
| if __name__ == "__main__": | |
| app.launch( | |
| share=False, | |
| server_name="0.0.0.0", | |
| server_port=7860, | |
| show_error=True, | |
| ) | |