altawil commited on
Commit
dd92815
·
verified ·
1 Parent(s): 48aa407

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +188 -394
app.py CHANGED
@@ -11,353 +11,6 @@ from pydantic import BaseModel
11
  from torchvision import transforms
12
  from typing import List, Dict, Any, Optional
13
  import logging
14
-
15
- # # استيراد من ملفاتنا المحلية
16
- # from model_definition import InterfuserModel, load_and_prepare_model, create_model_config
17
- # from simulation_modules import (
18
- # InterfuserController, ControllerConfig, Tracker, DisplayInterface,
19
- # render, render_waypoints, render_self_car, WAYPOINT_SCALE_FACTOR,
20
- # T1_FUTURE_TIME, T2_FUTURE_TIME
21
- # )
22
-
23
- # # إعداد التسجيل
24
- # logging.basicConfig(level=logging.INFO)
25
- # logger = logging.getLogger(__name__)
26
-
27
- # # ================== إعدادات عامة وتحميل النموذج ==================
28
- # app = FastAPI(
29
- # title="Baseer Self-Driving API",
30
- # description="API للقيادة الذاتية باستخدام نموذج InterFuser",
31
- # version="1.0.0"
32
- # )
33
-
34
- # device = torch.device("cpu")
35
- # logger.info(f"Using device: {device}")
36
-
37
- # # تحميل النموذج باستخدام الدالة المحسنة
38
- # try:
39
- # # إنشاء إعدادات النموذج باستخدام الإعدادات الصحيحة من التدريب
40
- # model_config = create_model_config(
41
- # model_path="model/best_model.pth"
42
- # # الإعدادات الصحيحة من التدريب ستطبق تلقائياً:
43
- # # embed_dim=256, rgb_backbone_name='r50', waypoints_pred_head='gru'
44
- # # with_lidar=False, with_right_left_sensors=False, with_center_sensor=False
45
- # )
46
-
47
- # # تحميل النموذج مع الأوزان
48
- # model = load_and_prepare_model(model_config, device)
49
- # logger.info("✅ تم تحميل النموذج بنجاح")
50
-
51
- # except Exception as e:
52
- # logger.error(f"❌ خطأ في تحميل النموذج: {e}")
53
- # logger.info("🔄 محاولة إنشاء نموذج بأوزان عشوائية...")
54
- # try:
55
- # model = InterfuserModel()
56
- # model.to(device)
57
- # model.eval()
58
- # logger.warning("⚠️ تم إنشاء النموذج بأوزان عشوائية")
59
- # except Exception as e2:
60
- # logger.error(f"❌ فشل في إنشاء النموذج: {e2}")
61
- # model = None
62
-
63
- # # تهيئة واجهة العرض
64
- # display = DisplayInterface()
65
-
66
- # # قاموس لتخزين جلسات المستخدمين
67
- # SESSIONS: Dict[str, Dict] = {}
68
-
69
- # # ================== هياكل بيانات Pydantic ==================
70
- # class Measurements(BaseModel):
71
- # pos: List[float] = [0.0, 0.0] # [x, y] position
72
- # theta: float = 0.0 # orientation angle
73
- # speed: float = 0.0 # current speed
74
- # steer: float = 0.0 # current steering
75
- # throttle: float = 0.0 # current throttle
76
- # brake: bool = False # brake status
77
- # command: int = 4 # driving command (4 = FollowLane)
78
- # target_point: List[float] = [0.0, 0.0] # target point [x, y]
79
-
80
- # class ModelOutputs(BaseModel):
81
- # traffic: List[List[List[float]]] # 20x20x7 grid
82
- # waypoints: List[List[float]] # Nx2 waypoints
83
- # is_junction: float
84
- # traffic_light_state: float
85
- # stop_sign: float
86
-
87
- # class ControlCommands(BaseModel):
88
- # steer: float
89
- # throttle: float
90
- # brake: bool
91
-
92
- # class RunStepInput(BaseModel):
93
- # session_id: str
94
- # image_b64: str
95
- # measurements: Measurements
96
-
97
- # class RunStepOutput(BaseModel):
98
- # model_outputs: ModelOutputs
99
- # control_commands: ControlCommands
100
- # dashboard_image_b64: str
101
-
102
- # class SessionResponse(BaseModel):
103
- # session_id: str
104
- # message: str
105
-
106
- # # ================== دوال المساعدة ==================
107
- # def get_image_transform():
108
- # """إنشاء تحويلات الصورة كما في PDMDataset"""
109
- # return transforms.Compose([
110
- # transforms.ToTensor(),
111
- # transforms.Resize((224, 224), antialias=True),
112
- # transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
113
- # ])
114
-
115
- # # إنشاء كائن التحويل مرة واحدة
116
- # image_transform = get_image_transform()
117
-
118
- # def preprocess_input(frame_rgb: np.ndarray, measurements: Measurements, device: torch.device) -> Dict[str, torch.Tensor]:
119
- # """
120
- # تحاكي ما يفعله PDMDataset.__getitem__ لإنشاء دفعة (batch) واحدة.
121
- # """
122
- # # 1. معالجة الصورة الرئيسية
123
- # from PIL import Image
124
- # if isinstance(frame_rgb, np.ndarray):
125
- # frame_rgb = Image.fromarray(frame_rgb)
126
-
127
- # image_tensor = image_transform(frame_rgb).unsqueeze(0).to(device) # إضافة بُعد الدفعة
128
-
129
- # # 2. إنشاء مدخلات الكاميرات الأخرى عن طريق الاستنساخ
130
- # batch = {
131
- # 'rgb': image_tensor,
132
- # 'rgb_left': image_tensor.clone(),
133
- # 'rgb_right': image_tensor.clone(),
134
- # 'rgb_center': image_tensor.clone(),
135
- # }
136
-
137
- # # 3. إنشاء مدخل ليدار وهمي (أصفار)
138
- # batch['lidar'] = torch.zeros(1, 3, 224, 224, dtype=torch.float32).to(device)
139
-
140
- # # 4. تجميع القياسات بنفس ترتيب PDMDataset
141
- # m = measurements
142
- # measurements_tensor = torch.tensor([[
143
- # m.pos[0], m.pos[1], m.theta,
144
- # m.steer, m.throttle, float(m.brake),
145
- # m.speed, float(m.command)
146
- # ]], dtype=torch.float32).to(device)
147
- # batch['measurements'] = measurements_tensor
148
-
149
- # # 5. إنشاء نقطة هدف
150
- # batch['target_point'] = torch.tensor([m.target_point], dtype=torch.float32).to(device)
151
-
152
- # # لا نحتاج إلى قيم ground truth (gt_*) أثناء التنبؤ
153
- # return batch
154
-
155
- # def decode_base64_image(image_b64: str) -> np.ndarray:
156
- # """
157
- # فك تشفير صورة Base64
158
- # """
159
- # try:
160
- # image_bytes = base64.b64decode(image_b64)
161
- # nparr = np.frombuffer(image_bytes, np.uint8)
162
- # image = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
163
- # return image
164
- # except Exception as e:
165
- # raise HTTPException(status_code=400, detail=f"Invalid image format: {str(e)}")
166
-
167
- # def encode_image_to_base64(image: np.ndarray) -> str:
168
- # """
169
- # تشفير صورة إلى Base64
170
- # """
171
- # _, buffer = cv2.imencode('.jpg', image, [cv2.IMWRITE_JPEG_QUALITY, 85])
172
- # return base64.b64encode(buffer).decode('utf-8')
173
-
174
- # # ================== نقاط نهاية الـ API ==================
175
- # @app.get("/", response_class=HTMLResponse)
176
- # async def root():
177
- # """
178
- # الصفحة الرئيسية للـ API
179
- # """
180
- # html_content = f"""
181
- # <!DOCTYPE html>
182
- # <html dir="rtl" lang="ar">
183
- # <head>
184
- # <meta charset="UTF-8">
185
- # <meta name="viewport" content="width=device-width, initial-scale=1.0">
186
- # <title>🚗 Baseer Self-Driving API</title>
187
- # <style>
188
- # * {{
189
- # margin: 0;
190
- # padding: 0;
191
- # box-sizing: border-box;
192
- # }}
193
- # body {{
194
- # font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
195
- # background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
196
- # min-height: 100vh;
197
- # display: flex;
198
- # align-items: center;
199
- # justify-content: center;
200
- # padding: 20px;
201
- # }}
202
- # .container {{
203
- # background: rgba(255, 255, 255, 0.95);
204
- # backdrop-filter: blur(10px);
205
- # border-radius: 20px;
206
- # padding: 40px;
207
- # box-shadow: 0 20px 40px rgba(0, 0, 0, 0.1);
208
- # text-align: center;
209
- # max-width: 600px;
210
- # width: 100%;
211
- # }}
212
- # .logo {{
213
- # font-size: 4rem;
214
- # margin-bottom: 20px;
215
- # animation: bounce 2s infinite;
216
- # }}
217
- # @keyframes bounce {{
218
- # 0%, 20%, 50%, 80%, 100% {{ transform: translateY(0); }}
219
- # 40% {{ transform: translateY(-10px); }}
220
- # 60% {{ transform: translateY(-5px); }}
221
- # }}
222
- # h1 {{
223
- # color: #333;
224
- # margin-bottom: 10px;
225
- # font-size: 2.5rem;
226
- # }}
227
- # .subtitle {{
228
- # color: #666;
229
- # margin-bottom: 30px;
230
- # font-size: 1.2rem;
231
- # }}
232
- # .status {{
233
- # display: inline-block;
234
- # background: #4CAF50;
235
- # color: white;
236
- # padding: 8px 16px;
237
- # border-radius: 20px;
238
- # margin: 10px 0;
239
- # font-weight: bold;
240
- # }}
241
- # .stats {{
242
- # display: grid;
243
- # grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
244
- # gap: 20px;
245
- # margin: 30px 0;
246
- # }}
247
- # .stat-card {{
248
- # background: #f8f9fa;
249
- # padding: 20px;
250
- # border-radius: 15px;
251
- # border-left: 4px solid #667eea;
252
- # }}
253
- # .stat-number {{
254
- # font-size: 2rem;
255
- # font-weight: bold;
256
- # color: #667eea;
257
- # }}
258
- # .stat-label {{
259
- # color: #666;
260
- # margin-top: 5px;
261
- # }}
262
- # .buttons {{
263
- # display: flex;
264
- # gap: 15px;
265
- # justify-content: center;
266
- # flex-wrap: wrap;
267
- # margin-top: 30px;
268
- # }}
269
- # .btn {{
270
- # display: inline-block;
271
- # padding: 12px 24px;
272
- # border-radius: 25px;
273
- # text-decoration: none;
274
- # font-weight: bold;
275
- # transition: all 0.3s ease;
276
- # border: none;
277
- # cursor: pointer;
278
- # }}
279
- # .btn-primary {{
280
- # background: #667eea;
281
- # color: white;
282
- # }}
283
- # .btn-secondary {{
284
- # background: #6c757d;
285
- # color: white;
286
- # }}
287
- # .btn:hover {{
288
- # transform: translateY(-2px);
289
- # box-shadow: 0 5px 15px rgba(0, 0, 0, 0.2);
290
- # }}
291
- # .features {{
292
- # text-align: right;
293
- # margin-top: 30px;
294
- # padding: 20px;
295
- # background: #f8f9fa;
296
- # border-radius: 15px;
297
- # }}
298
- # .features h3 {{
299
- # color: #333;
300
- # margin-bottom: 15px;
301
- # }}
302
- # .features ul {{
303
- # list-style: none;
304
- # padding: 0;
305
- # }}
306
- # .features li {{
307
- # padding: 5px 0;
308
- # color: #666;
309
- # }}
310
- # .features li:before {{
311
- # content: "✅ ";
312
- # margin-left: 10px;
313
- # }}
314
- # </style>
315
- # </head>
316
- # <body>
317
- # <div class="container">
318
- # <div class="logo">🚗</div>
319
- # <h1>Baseer Self-Driving API</h1>
320
- # <p class="subtitle">نظام القيادة الذاتية المتقدم</p>
321
-
322
- # <div class="status">🟢 يعمل بنجاح</div>
323
-
324
- # <div class="stats">
325
- # <div class="stat-card">
326
- # <div class="stat-number">{len(SESSIONS)}</div>
327
- # <div class="stat-label">الجلسات النشطة</div>
328
- # </div>
329
- # <div class="stat-card">
330
- # <div class="stat-number">v1.0</div>
331
- # <div class="stat-label">الإصدار</div>
332
- # </div>
333
- # <div class="stat-card">
334
- # <div class="stat-number">FastAPI</div>
335
- # <div class="stat-label">التقنية</div>
336
- # </div>
337
- # </div>
338
-
339
- # <div class="buttons">
340
- # <a href="/docs" class="btn btn-primary">📚 توثيق API</a>
341
- # <a href="/sessions" class="btn btn-secondary">📊 الجلسات</a>
342
- # </div>
343
-
344
- # <div class="features">
345
- # <h3>🌟 الميزات الرئيسية</h3>
346
- # <ul>
347
- # <li>نموذج InterFuser للقيادة الذاتية</li>
348
- # <li>معالجة الصور في الوقت الفعلي</li>
349
- # <li>اكتشاف الكائنات المرورية</li>
350
- # <li>تحديد المسارات الذكية</li>
351
- # <li>واجهة RESTful سهلة الاستخدام</li>
352
- # <li>إدارة جلسات متعددة</li>
353
- # </ul>
354
- # </div>
355
- # </div>
356
- # </body>
357
- # </html>
358
- # """
359
- # return html_content
360
-
361
  import uuid
362
  import base64
363
  import cv2
@@ -369,23 +22,12 @@ from fastapi.responses import HTMLResponse
369
  from pydantic import BaseModel, Field
370
  from typing import List, Dict, Tuple
371
 
372
- # ==============================================================================
373
- # 1. استيراد كل مكونات المشروع التي قمنا بتطويرها
374
- # (تأكد من أن هذه الملفات موجودة في نفس المجلد)
375
- # ==============================================================================
376
- # من ملف النموذج (يحتوي على كلاس Interfuser والدوال المساعدة)
377
  from model_definition import InterfuserModel, load_and_prepare_model, get_master_config
378
 
379
- # من ملفات التحكم والعرض
380
  from simulation_modules import InterfuserController, Tracker
381
  from simulation_modules import DisplayInterface, render_bev, unnormalize_image, DisplayConfig
382
- # # استيراد من ملفاتنا المحلية
383
- # from model_definition import InterfuserModel, load_and_prepare_model, create_model_config
384
- # from simulation_modules import (
385
- # InterfuserController, ControllerConfig, Tracker, DisplayInterface,
386
- # render, render_waypoints, render_self_car, WAYPOINT_SCALE_FACTOR,
387
- # T1_FUTURE_TIME, T2_FUTURE_TIME
388
- # )
389
  # ==============================================================================
390
  # 2. إعدادات عامة وتطبيق FastAPI
391
  # ==============================================================================
@@ -477,9 +119,7 @@ def prepare_model_input(image: np.ndarray, measurements: Measurements) -> Dict[s
477
  'target_point': target_point_tensor,
478
  'lidar': torch.zeros_like(image_tensor)
479
  }
480
- # model_config = create_model_config(
481
- # model_path="model/best_model.pth"
482
- # )
483
  # ==============================================================================
484
  # 5. أحداث دورة حياة التطبيق (Startup/Shutdown)
485
  # ==============================================================================
@@ -494,44 +134,198 @@ async def startup_event():
494
  logging.info("✅ Model loaded successfully. Server is ready!")
495
  else:
496
  logging.error("❌ CRITICAL: Model could not be loaded. The API will not function correctly.")
497
- # # تحميل النموذج باستخدام الدالة المحسنة
498
- # try:
499
- # # إنشاء إعدادات النموذج باستخدام الإعدادات الصحيحة من التدريب
500
-
501
-
502
- # # تحميل النموذج مع الأوزان
503
- #
504
- # logger.info("✅ تم تحميل النموذج بنجاح")
505
-
506
- # except Exception as e:
507
- # logger.error(f"❌ خطأ في تحميل النموذج: {e}")
508
- # logger.info("🔄 محاولة إنشاء نموذج بأوزان عشوائية...")
509
- # try:
510
- # model = InterfuserModel()
511
- # model.to(device)
512
- # model.eval()
513
- # logger.warning("⚠️ تم إنشاء النموذج بأوزان عشوائية")
514
- # except Exception as e2:
515
- # logger.error(f"❌ فشل في إنشاء النموذج: {e2}")
516
- # model = None
517
 
518
  # ==============================================================================
519
  # 6. نقاط النهاية الرئيسية (API Endpoints)
520
  # ==============================================================================
521
- @app.get("/", response_class=HTMLResponse, include_in_schema=False)
 
522
  async def root():
523
- # هذا يعرض صفحة رئيسية بسيطة وجميلة للمستخدمين
524
- return """
525
- <html>
526
- <head><title>Baseer API</title></head>
527
- <body style='font-family: sans-serif; text-align: center; padding-top: 50px;'>
528
- <h1>🚗 Baseer Self-Driving API</h1>
529
- <p>Welcome! The API is running.</p>
530
- <p>Navigate to <a href="/docs">/docs</a> for the interactive API documentation.</p>
531
- </body>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
532
  </html>
533
  """
534
- # في ملف app.py
535
 
536
  @app.post("/start_session", summary="Start a new driving session", tags=["Session Management"])
537
  def start_session():
 
11
  from torchvision import transforms
12
  from typing import List, Dict, Any, Optional
13
  import logging
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  import uuid
15
  import base64
16
  import cv2
 
22
  from pydantic import BaseModel, Field
23
  from typing import List, Dict, Tuple
24
 
 
 
 
 
 
25
  from model_definition import InterfuserModel, load_and_prepare_model, get_master_config
26
 
27
+
28
  from simulation_modules import InterfuserController, Tracker
29
  from simulation_modules import DisplayInterface, render_bev, unnormalize_image, DisplayConfig
30
+
 
 
 
 
 
 
31
  # ==============================================================================
32
  # 2. إعدادات عامة وتطبيق FastAPI
33
  # ==============================================================================
 
119
  'target_point': target_point_tensor,
120
  'lidar': torch.zeros_like(image_tensor)
121
  }
122
+
 
 
123
  # ==============================================================================
124
  # 5. أحداث دورة حياة التطبيق (Startup/Shutdown)
125
  # ==============================================================================
 
134
  logging.info("✅ Model loaded successfully. Server is ready!")
135
  else:
136
  logging.error("❌ CRITICAL: Model could not be loaded. The API will not function correctly.")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
 
138
  # ==============================================================================
139
  # 6. نقاط النهاية الرئيسية (API Endpoints)
140
  # ==============================================================================
141
+
142
+ @app.get("/", response_class=HTMLResponse, include_in_schema=False, tags=["General"])
143
  async def root():
144
+ """
145
+ يعرض صفحة رئيسية احترافية وتفاعلية لواجهة برمجة التطبيقات.
146
+ """
147
+ # الحصول على عدد الجلسات النشطة حاليًا
148
+ active_sessions_count = len(SESSIONS)
149
+
150
+ # تحديد لون حالة النظام
151
+ status_color = "#4CAF50" # أخضر
152
+ status_text = "يعمل بنجاح"
153
+ if MODEL is None:
154
+ status_color = "#F44336" # أحمر
155
+ status_text = "خطأ: النموذج غير محمل"
156
+
157
+ html_content = f"""
158
+ <!DOCTYPE html>
159
+ <html dir="rtl" lang="ar">
160
+ <head>
161
+ <meta charset="UTF-8">
162
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
163
+ <title>🚗 Baseer Self-Driving API</title>
164
+ <style>
165
+ @import url('https://fonts.googleapis.com/css2?family=Tajawal:wght@400;700&display=swap');
166
+
167
+ :root {{
168
+ --primary-color: #4a69bd;
169
+ --secondary-color: #6a89cc;
170
+ --text-color: #333;
171
+ --bg-color: #f4f7f6;
172
+ --panel-bg: #ffffff;
173
+ --shadow: 0 10px 30px rgba(0, 0, 0, 0.1);
174
+ }}
175
+
176
+ body {{
177
+ font-family: 'Tajawal', sans-serif;
178
+ background-color: var(--bg-color);
179
+ color: var(--text-color);
180
+ margin: 0;
181
+ display: flex;
182
+ justify-content: center;
183
+ align-items: center;
184
+ min-height: 100vh;
185
+ padding: 20px;
186
+ }}
187
+
188
+ .container {{
189
+ background: var(--panel-bg);
190
+ border-radius: 20px;
191
+ padding: 40px;
192
+ box-shadow: var(--shadow);
193
+ text-align: center;
194
+ max-width: 700px;
195
+ width: 100%;
196
+ border-top: 5px solid var(--primary-color);
197
+ }}
198
+
199
+ .logo {{
200
+ font-size: 4rem;
201
+ margin-bottom: 15px;
202
+ animation: car-drive 3s ease-in-out infinite;
203
+ }}
204
+
205
+ @keyframes car-drive {{
206
+ 0% {{ transform: translateX(-20px); }}
207
+ 50% {{ transform: translateX(20px); }}
208
+ 100% {{ transform: translateX(-20px); }}
209
+ }}
210
+
211
+ h1 {{
212
+ font-size: 2.8rem;
213
+ font-weight: 700;
214
+ color: var(--primary-color);
215
+ margin-bottom: 10px;
216
+ }}
217
+
218
+ .subtitle {{
219
+ font-size: 1.2rem;
220
+ color: #777;
221
+ margin-bottom: 25px;
222
+ }}
223
+
224
+ .status-badge {{
225
+ display: inline-block;
226
+ background-color: {status_color};
227
+ color: white;
228
+ padding: 10px 20px;
229
+ border-radius: 25px;
230
+ font-weight: bold;
231
+ margin-bottom: 30px;
232
+ font-size: 1rem;
233
+ }}
234
+
235
+ .stats-grid {{
236
+ display: grid;
237
+ grid-template-columns: 1fr 1fr;
238
+ gap: 20px;
239
+ margin-bottom: 30px;
240
+ }}
241
+
242
+ .stat-card {{
243
+ background: #f8f9fa;
244
+ padding: 20px;
245
+ border-radius: 15px;
246
+ }}
247
+
248
+ .stat-number {{
249
+ font-size: 2.5rem;
250
+ font-weight: 700;
251
+ color: var(--primary-color);
252
+ }}
253
+
254
+ .stat-label {{
255
+ font-size: 1rem;
256
+ color: #666;
257
+ margin-top: 5px;
258
+ }}
259
+
260
+ .button-group {{
261
+ display: flex;
262
+ gap: 15px;
263
+ justify-content: center;
264
+ }}
265
+
266
+ .btn {{
267
+ padding: 14px 28px;
268
+ border-radius: 30px;
269
+ text-decoration: none;
270
+ font-weight: bold;
271
+ font-size: 1rem;
272
+ transition: all 0.3s ease;
273
+ border: 2px solid transparent;
274
+ cursor: pointer;
275
+ }}
276
+
277
+ .btn-primary {{
278
+ background: var(--primary-color);
279
+ color: white;
280
+ }}
281
+
282
+ .btn-primary:hover {{
283
+ background: var(--secondary-color);
284
+ transform: translateY(-3px);
285
+ }}
286
+
287
+ .btn-secondary {{
288
+ background: transparent;
289
+ color: var(--primary-color);
290
+ border-color: var(--primary-color);
291
+ }}
292
+
293
+ .btn-secondary:hover {{
294
+ background: var(--primary-color);
295
+ color: white;
296
+ transform: translateY(-3px);
297
+ }}
298
+
299
+ </style>
300
+ </head>
301
+ <body>
302
+ <div class="container">
303
+ <div class="logo">🚗</div>
304
+ <h1>Baseer Self-Driving API</h1>
305
+ <p class="subtitle">واجهة برمجية متقدمة للقيادة الذاتية</p>
306
+
307
+ <div class="status-badge">{status_text}</div>
308
+
309
+ <div class="stats-grid">
310
+ <div class="stat-card">
311
+ <div class="stat-number">{active_sessions_count}</div>
312
+ <div class="stat-label">الجلسات النشطة</div>
313
+ </div>
314
+ <div class="stat-card">
315
+ <div class="stat-number">1.1.0</div>
316
+ <div class="stat-label">إصدار الـ API</div>
317
+ </div>
318
+ </div>
319
+
320
+ <div class="button-group">
321
+ <a href="/docs" target="_blank" class="btn btn-primary">📚 التوثيق التفاعلي (Docs)</a>
322
+ <a href="/sessions" target="_blank" class="btn btn-secondary">📊 عرض الجلسات</a>
323
+ </div>
324
+ </div>
325
+ </body>
326
  </html>
327
  """
328
+ return HTMLResponse(content=html_content)
329
 
330
  @app.post("/start_session", summary="Start a new driving session", tags=["Session Management"])
331
  def start_session():