mohammed-aljafry commited on
Commit
29e1e9d
·
verified ·
1 Parent(s): 034c3f1

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +64 -109
app.py CHANGED
@@ -1,12 +1,12 @@
1
  # ============================================================================
2
  # app.py - الواجهة التفاعلية لمشروع Interfuser
3
  # ============================================================================
4
- # هذا الملف يقوم بإنشاء واجهة ويب باستخدام Gradio لعرض أداء نموذج
5
- # Interfuser للقيادة الذاتية. يسمح للمستخدمين باختيار نماذج مختلفة
6
- # وسيناريوهات قيادة ومقارنة النتائج.
 
7
  # ============================================================================
8
 
9
- # --- الجزء الأول: الاستيرادات ---
10
  import os
11
  import torch
12
  import numpy as np
@@ -15,17 +15,16 @@ import json
15
  import logging
16
  import traceback
17
  from PIL import Image
18
- from typing import Dict
19
 
20
  # مكتبة الواجهة الرسومية
21
  import gradio as gr
22
 
23
- # مكتبات معالجة الصور من Torch
24
  from torchvision import transforms
25
 
26
- # استيراد الوحدات الخاصة بنا من الملفات الأخرى
27
  try:
28
- from model_definition import load_and_prepare_model, create_model_config
29
  from simulation_modules import (
30
  DisplayInterface,
31
  InterfuserController,
@@ -35,18 +34,16 @@ try:
35
  render
36
  )
37
  except ImportError as e:
38
- print(f"خطأ في الاستيراد: تأكد من وجود ملفات model_definition.py و simulation_modules.py. الخطأ: {e}")
39
  exit()
40
 
41
  # --- الجزء الثاني: الإعدادات والثوابت ---
42
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
43
 
44
- DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
45
- MODEL_DIR = "model"
46
  SAMPLE_DATA_DIR = "sample_data"
 
47
 
48
- # --- الجزء الثالث: تعريف التحويلات (Transforms) ---
49
- # هذه التحويلات يجب أن تطابق تمامًا ما تم استخدامه أثناء تدريب النموذج
50
  RGB_TRANSFORM = transforms.Compose([
51
  transforms.Resize((224, 224)),
52
  transforms.ToTensor(),
@@ -58,89 +55,57 @@ LIDAR_TRANSFORM = transforms.Compose([
58
  transforms.ToTensor()
59
  ])
60
 
61
- # --- الجزء الرابع: الكائنات العامة ومخبأ النماذج ---
62
- logging.info("تهيئة المكونات العامة...")
63
- # قاموس لتخزين النماذج التي تم تحميلها لتجنب إعادة التحميل البطيئة
64
- GLOBAL_MODELS_CACHE: Dict[str, torch.nn.Module] = {}
65
-
66
- # تهيئة واجهة العرض والمتحكم (يتم تهيئتها مرة واحدة)
67
  GLOBAL_DISPLAY_INTERFACE = DisplayInterface()
68
  controller_config = ControllerConfig()
69
  GLOBAL_CONTROLLER = InterfuserController(controller_config)
70
- logging.info(f"تم تهيئة المكونات. يعمل التطبيق على الجهاز: {DEVICE}")
71
-
72
- # --- الجزء الخامس: دوال المساعدة والمعالجة ---
73
-
74
- def get_model(model_name: str) -> torch.nn.Module:
75
- """
76
- تقوم بتحميل النموذج إذا لم يكن في المخبأ، ثم تعيده.
77
- """
78
- if model_name in GLOBAL_MODELS_CACHE:
79
- logging.info(f"إعادة استخدام النموذج '{model_name}' من المخبأ.")
80
- return GLOBAL_MODELS_CACHE[model_name]
81
-
82
- logging.info(f"النموذج '{model_name}' غير موجود في المخبأ. بدء التحميل...")
83
- gr.Info(f"⏳ جاري تحميل نموذج جديد: {model_name}... قد يستغرق هذا بضع ثوانٍ.")
84
-
85
- model_path = os.path.join(MODEL_DIR, model_name)
86
- if not os.path.exists(model_path):
87
- raise FileNotFoundError(f"ملف النموذج '{model_path}' غير موجود!")
88
-
89
- model_config = create_model_config(model_path=model_path)
90
- model = load_and_prepare_model(model_config, DEVICE)
91
-
92
- if model:
93
- GLOBAL_MODELS_CACHE[model_name] = model
94
- logging.info(f"✅ تم تحميل وتخزين النموذج '{model_name}' في المخبأ.")
95
- return model
96
- else:
97
- raise gr.Error(f"فشل تحميل النموذج '{model_name}'. يرجى مراجعة السجلات.")
98
 
 
99
 
100
- def process_and_run_model(
101
  model: torch.nn.Module,
102
- rgb_image_path: str, rgb_left_image_path: str, rgb_right_image_path: str,
103
- rgb_center_image_path: str, lidar_image_path: str,
104
- measurements_path: str, target_point_list: list
105
  ):
106
  """
107
- محرك المعالجة: يعالج إطارًا واحدًا من البيانات بناءً على المسارات
108
- ويقوم بتشغيل النموذج عليه.
109
  """
110
  try:
111
- # 1. قراءة ومعالجة المدخلات
112
- if not rgb_image_path or not os.path.exists(rgb_image_path):
113
  raise FileNotFoundError("ملف الصورة الأمامية (RGB) غير موجود.")
114
 
115
- rgb_image = Image.open(rgb_image_path).convert("RGB")
116
 
117
  def open_optional_image(path, default_img):
118
  return Image.open(path).convert("RGB") if path and os.path.exists(path) else default_img
119
 
120
- rgb_left_image = open_optional_image(rgb_left_image_path, rgb_image)
121
- rgb_right_image = open_optional_image(rgb_right_image_path, rgb_image)
122
- rgb_center_image = open_optional_image(rgb_center_image_path, rgb_image)
123
 
124
- if lidar_image_path and os.path.exists(lidar_image_path):
125
- lidar_array = np.load(lidar_image_path)
 
126
  max_val = lidar_array.max()
127
  if max_val > 0: lidar_array = (lidar_array / max_val) * 255.0
128
  lidar_image = Image.fromarray(lidar_array.astype(np.uint8)).convert('RGB')
129
  else:
130
  lidar_image = Image.fromarray(np.zeros((224, 224, 3), dtype=np.uint8))
131
 
132
- # 2. تطبيق التحويلات
 
133
  inputs = {
134
  'rgb': RGB_TRANSFORM(rgb_image).unsqueeze(0).to(DEVICE),
135
  'rgb_left': RGB_TRANSFORM(rgb_left_image).unsqueeze(0).to(DEVICE),
136
  'rgb_right': RGB_TRANSFORM(rgb_right_image).unsqueeze(0).to(DEVICE),
137
  'rgb_center': RGB_TRANSFORM(rgb_center_image).unsqueeze(0).to(DEVICE),
138
  'lidar': LIDAR_TRANSFORM(lidar_image).unsqueeze(0).to(DEVICE),
139
- 'measurements': torch.tensor([json.load(open(measurements_path))['values']], dtype=torch.float32).to(DEVICE),
140
  'target_point': torch.tensor([target_point_list], dtype=torch.float32).to(DEVICE)
141
  }
142
 
143
- # 3. تشغيل النموذج
144
  with torch.no_grad():
145
  outputs = model(inputs)
146
 
@@ -151,16 +116,16 @@ def process_and_run_model(
151
  raise gr.Error(f"حدث خطأ أثناء معالجة البيانات: {e}")
152
 
153
 
154
- def run_simulation(model_name: str, scenario_name: str):
155
  """
156
  المنسق الرئيسي: يجهز المدخلات، يستدعي محرك المعالجة، ثم يعرض النتائج.
157
  """
158
- logging.info(f"بدء المحاكاة للنموذج: '{model_name}', السيناريو: '{scenario_name}'")
159
 
160
- # 1. احصل على النموذج (من المخبأ أو قم بتحميله)
161
- model = get_model(model_name)
 
162
 
163
- # 2. جهز المسارات للسيناريو المختار
164
  scenario_path = os.path.join(SAMPLE_DATA_DIR, scenario_name)
165
  paths = {
166
  'rgb': os.path.join(scenario_path, 'rgb.png'),
@@ -172,22 +137,12 @@ def run_simulation(model_name: str, scenario_name: str):
172
  'target_point': os.path.join(scenario_path, 'target_point.json')
173
  }
174
 
175
- # 3. استدعاء محرك المعالجة والنموذج
176
- target_point_list = json.load(open(paths['target_point']))['value']
177
-
178
- traffic, waypoints, is_junction, traffic_light, stop_sign, _ = process_and_run_model(
179
- model=model, rgb_image_path=paths['rgb'], rgb_left_image_path=paths['left'],
180
- rgb_right_image_path=paths['right'], rgb_center_image_path=paths['center'],
181
- lidar_image_path=paths['lidar'], measurements_path=paths['measurements'],
182
- target_point_list=target_point_list
183
- )
184
 
185
- # 4. معالجة المخرجات
186
  pred_wp = waypoints[0].cpu().numpy()
187
  pred_traffic_map = traffic[0].sigmoid().cpu().numpy().reshape(20, 20, 7)
188
- current_speed = json.load(open(paths['measurements'])).get('values', [0]*7)[3] # Speed is at index 3
189
 
190
- # 5. استخدام متحكم القيادة للحصول على الأوامر
191
  steer, throttle, brake, metadata = GLOBAL_CONTROLLER.run_step(
192
  current_speed=current_speed, waypoints=pred_wp,
193
  junction=torch.sigmoid(is_junction)[0,1].item(),
@@ -196,19 +151,15 @@ def run_simulation(model_name: str, scenario_name: str):
196
  meta_data={}
197
  )
198
 
199
- # 6. إنشاء الخرائط المرئية
200
  traffic_render, _ = render(pred_traffic_map)
201
  waypoints_render = render_waypoints(pred_wp)
202
  combined_map = cv2.addWeighted(traffic_render, 1.0, waypoints_render, 1.0, 0.0)
203
  final_map = render_self_car(combined_map)
204
 
205
- # 7. تجهيز البيانات النهائية للعرض
206
  display_data = {
207
  'camera_view': np.array(Image.open(paths['rgb'])),
208
  'map_t0': final_map, 'map_t1': np.zeros_like(final_map), 'map_t2': np.zeros_like(final_map),
209
  'text_info': {
210
- "Model": f"Model: {model_name}",
211
- "Scenario": f"Scenario: {scenario_name}",
212
  "Controller": metadata,
213
  "Brake": f"Brake Activated: {'YES' if brake else 'NO'}"
214
  }
@@ -220,36 +171,26 @@ def run_simulation(model_name: str, scenario_name: str):
220
  return dashboard, metadata
221
 
222
 
223
- # --- الجزء السادس: بناء واجهة Gradio ---
224
  with gr.Blocks(title="Interfuser Demo", theme=gr.themes.Soft()) as demo:
225
  gr.Markdown("# 🚀 Interfuser: واجهة القيادة التفاعلية")
226
  gr.Markdown("اختر النموذج والسيناريو، ثم اضغط على 'تشغيل' للمقارنة بين أداء النماذج المختلفة.")
227
 
228
- # قراءة النماذج والسيناريوهات المتاحة من المجلدات
229
  try:
230
- # 💡 أضف هذين السطرين للطباعة التشخيصية
231
- print("================== DEBUGGING ==================")
232
- print(f"🔍 Current working directory is: {os.getcwd()}")
233
- print(f"📂 Searching for models in folder: {os.path.abspath(MODEL_DIR)}")
234
-
235
- available_models = [f for f in os.listdir(MODEL_DIR) if f.endswith(('.pth', '.pt'))]
236
-
237
- # 💡 وهذا السطر أيضًا
238
- print(f"✅ Found models: {available_models}")
239
- print("=============================================")
240
-
241
  available_scenarios = [d for d in os.listdir(SAMPLE_DATA_DIR) if os.path.isdir(os.path.join(SAMPLE_DATA_DIR, d))]
242
  except FileNotFoundError as e:
243
- gr.Error(f"خطأ في إعداد الواجهة: {e}. هل قمت بإنشاء مجلدي 'model' و 'sample_data'؟")
244
- available_models = []
245
- available_scenarios = []
246
 
247
  with gr.Row():
248
  with gr.Column(scale=1, min_width=300):
249
- # مدخلات المستخدم
250
  model_selector = gr.Dropdown(
251
  choices=available_models, label="1. اختر النموذج",
252
- value=available_models[0] if available_models else None)
 
 
 
253
 
254
  scenario_selector = gr.Dropdown(
255
  choices=available_scenarios, label="2. اختر سيناريو القيادة",
@@ -257,23 +198,37 @@ with gr.Blocks(title="Interfuser Demo", theme=gr.themes.Soft()) as demo:
257
 
258
  run_button = gr.Button("▶️ تشغيل المحاكاة", variant="primary")
259
 
260
- # مخرجات نصية
261
  controller_output = gr.Textbox(label="بيانات متحكم القيادة", interactive=False)
262
 
263
  with gr.Column(scale=3):
264
- # مخرجات مرئية
265
  dashboard_output = gr.Image(label="لوحة المعلومات الحية (Dashboard)", interactive=False)
266
 
267
- # ربط زر التشغيل بالدالة الرئيسية
 
 
 
 
 
 
 
 
 
268
  if available_models and available_scenarios:
269
  run_button.click(
270
  fn=run_simulation,
271
- inputs=[model_selector, scenario_selector],
272
  outputs=[dashboard_output, controller_output]
273
  )
274
  else:
275
  gr.Warning("لا يمكن العثور على نماذج أو سيناريوهات. يرجى التأكد من إعداد المجلدات بشكل صحيح.")
 
 
 
 
 
 
 
276
 
277
- # --- الجزء السابع: إطلاق الواجهة ---
278
  if __name__ == "__main__":
279
- demo.launch(debug=True) # استخدم debug=True للمساعدة في اكتشاف الأخطاء أثناء التطوير
 
1
  # ============================================================================
2
  # app.py - الواجهة التفاعلية لمشروع Interfuser
3
  # ============================================================================
4
+ # هذا الملف مسؤول فقط عن بناء وتشغيل واجهة المستخدم باستخدام Gradio.
5
+ # يعتمد على:
6
+ # - model_utils.py: لإدارة وتحميل النماذج.
7
+ # - simulation_modules.py: لمعالجة المخرجات والتحكم والعرض.
8
  # ============================================================================
9
 
 
10
  import os
11
  import torch
12
  import numpy as np
 
15
  import logging
16
  import traceback
17
  from PIL import Image
 
18
 
19
  # مكتبة الواجهة الرسومية
20
  import gradio as gr
21
 
22
+ # مكتبات معالجة الصور
23
  from torchvision import transforms
24
 
25
+ # --- الجزء الأول: استيراد الوحدات الخاصة بنا ---
26
  try:
27
+ from model_utils import get_available_models, load_model_by_name, get_current_model
28
  from simulation_modules import (
29
  DisplayInterface,
30
  InterfuserController,
 
34
  render
35
  )
36
  except ImportError as e:
37
+ print(f"خطأ في الاستيراد: تأكد من وجود ملفات model_utils.py و simulation_modules.py. الخطأ: {e}")
38
  exit()
39
 
40
  # --- الجزء الثاني: الإعدادات والثوابت ---
41
  logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
42
 
 
 
43
  SAMPLE_DATA_DIR = "sample_data"
44
+ DEVICE = torch.device("cuda" if torch.cuda.is_available() else "cpu")
45
 
46
+ # تعريف التحويلات (يجب أن تطابق ما تم استخدامه أثناء التدريب)
 
47
  RGB_TRANSFORM = transforms.Compose([
48
  transforms.Resize((224, 224)),
49
  transforms.ToTensor(),
 
55
  transforms.ToTensor()
56
  ])
57
 
58
+ # --- الجزء الثالث: الكائنات العامة للواجهة ---
59
+ logging.info("تهيئة مكونات الواجهة...")
 
 
 
 
60
  GLOBAL_DISPLAY_INTERFACE = DisplayInterface()
61
  controller_config = ControllerConfig()
62
  GLOBAL_CONTROLLER = InterfuserController(controller_config)
63
+ logging.info(f"تم تهيئة مكونات الواجهة. الجهاز المستخدم: {DEVICE}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
64
 
65
+ # --- الجزء الرابع: دوال المعالجة الرئيسية ---
66
 
67
+ def process_and_run_inference(
68
  model: torch.nn.Module,
69
+ paths: dict
 
 
70
  ):
71
  """
72
+ محرك المعالجة: يعالج بيانات إطار واحد بناءً على المسارات ويشغل النموذج.
 
73
  """
74
  try:
75
+ rgb_path = paths['rgb']
76
+ if not rgb_path or not os.path.exists(rgb_path):
77
  raise FileNotFoundError("ملف الصورة الأمامية (RGB) غير موجود.")
78
 
79
+ rgb_image = Image.open(rgb_path).convert("RGB")
80
 
81
  def open_optional_image(path, default_img):
82
  return Image.open(path).convert("RGB") if path and os.path.exists(path) else default_img
83
 
84
+ rgb_left_image = open_optional_image(paths.get('left'), rgb_image)
85
+ rgb_right_image = open_optional_image(paths.get('right'), rgb_image)
86
+ rgb_center_image = open_optional_image(paths.get('center'), rgb_image)
87
 
88
+ lidar_path = paths.get('lidar')
89
+ if lidar_path and os.path.exists(lidar_path):
90
+ lidar_array = np.load(lidar_path)
91
  max_val = lidar_array.max()
92
  if max_val > 0: lidar_array = (lidar_array / max_val) * 255.0
93
  lidar_image = Image.fromarray(lidar_array.astype(np.uint8)).convert('RGB')
94
  else:
95
  lidar_image = Image.fromarray(np.zeros((224, 224, 3), dtype=np.uint8))
96
 
97
+ target_point_list = json.load(open(paths['target_point']))['value']
98
+
99
  inputs = {
100
  'rgb': RGB_TRANSFORM(rgb_image).unsqueeze(0).to(DEVICE),
101
  'rgb_left': RGB_TRANSFORM(rgb_left_image).unsqueeze(0).to(DEVICE),
102
  'rgb_right': RGB_TRANSFORM(rgb_right_image).unsqueeze(0).to(DEVICE),
103
  'rgb_center': RGB_TRANSFORM(rgb_center_image).unsqueeze(0).to(DEVICE),
104
  'lidar': LIDAR_TRANSFORM(lidar_image).unsqueeze(0).to(DEVICE),
105
+ 'measurements': torch.tensor([json.load(open(paths['measurements']))['values']], dtype=torch.float32).to(DEVICE),
106
  'target_point': torch.tensor([target_point_list], dtype=torch.float32).to(DEVICE)
107
  }
108
 
 
109
  with torch.no_grad():
110
  outputs = model(inputs)
111
 
 
116
  raise gr.Error(f"حدث خطأ أثناء معالجة البيانات: {e}")
117
 
118
 
119
+ def run_simulation(scenario_name: str):
120
  """
121
  المنسق الرئيسي: يجهز المدخلات، يستدعي محرك المعالجة، ثم يعرض النتائج.
122
  """
123
+ logging.info(f"بدء المحاكاة للسيناريو: '{scenario_name}'")
124
 
125
+ model = get_current_model()
126
+ if model is None:
127
+ raise gr.Error("لا يوجد نموذج محمل. يرجى اختيار نموذج من القائمة أولاً.")
128
 
 
129
  scenario_path = os.path.join(SAMPLE_DATA_DIR, scenario_name)
130
  paths = {
131
  'rgb': os.path.join(scenario_path, 'rgb.png'),
 
137
  'target_point': os.path.join(scenario_path, 'target_point.json')
138
  }
139
 
140
+ traffic, waypoints, is_junction, traffic_light, stop_sign, _ = process_and_run_inference(model, paths)
 
 
 
 
 
 
 
 
141
 
 
142
  pred_wp = waypoints[0].cpu().numpy()
143
  pred_traffic_map = traffic[0].sigmoid().cpu().numpy().reshape(20, 20, 7)
144
+ current_speed = json.load(open(paths['measurements'])).get('values', [0]*7)[3]
145
 
 
146
  steer, throttle, brake, metadata = GLOBAL_CONTROLLER.run_step(
147
  current_speed=current_speed, waypoints=pred_wp,
148
  junction=torch.sigmoid(is_junction)[0,1].item(),
 
151
  meta_data={}
152
  )
153
 
 
154
  traffic_render, _ = render(pred_traffic_map)
155
  waypoints_render = render_waypoints(pred_wp)
156
  combined_map = cv2.addWeighted(traffic_render, 1.0, waypoints_render, 1.0, 0.0)
157
  final_map = render_self_car(combined_map)
158
 
 
159
  display_data = {
160
  'camera_view': np.array(Image.open(paths['rgb'])),
161
  'map_t0': final_map, 'map_t1': np.zeros_like(final_map), 'map_t2': np.zeros_like(final_map),
162
  'text_info': {
 
 
163
  "Controller": metadata,
164
  "Brake": f"Brake Activated: {'YES' if brake else 'NO'}"
165
  }
 
171
  return dashboard, metadata
172
 
173
 
174
+ # --- الجزء الخامس: بناء واجهة Gradio ---
175
  with gr.Blocks(title="Interfuser Demo", theme=gr.themes.Soft()) as demo:
176
  gr.Markdown("# 🚀 Interfuser: واجهة القيادة التفاعلية")
177
  gr.Markdown("اختر النموذج والسيناريو، ثم اضغط على 'تشغيل' للمقارنة بين أداء النماذج المختلفة.")
178
 
 
179
  try:
180
+ available_models = get_available_models()
 
 
 
 
 
 
 
 
 
 
181
  available_scenarios = [d for d in os.listdir(SAMPLE_DATA_DIR) if os.path.isdir(os.path.join(SAMPLE_DATA_DIR, d))]
182
  except FileNotFoundError as e:
183
+ gr.Error(f"خطأ في الإعداد: {e}. هل قمت بإنشاء مجلدي 'model' و 'sample_data'؟")
184
+ available_models, available_scenarios = [], []
 
185
 
186
  with gr.Row():
187
  with gr.Column(scale=1, min_width=300):
 
188
  model_selector = gr.Dropdown(
189
  choices=available_models, label="1. اختر النموذج",
190
+ value=available_models[0] if available_models else None,
191
+ interactive=True
192
+ )
193
+ model_load_status = gr.Textbox(label="حالة تحميل النموذج", interactive=False)
194
 
195
  scenario_selector = gr.Dropdown(
196
  choices=available_scenarios, label="2. اختر سيناريو القيادة",
 
198
 
199
  run_button = gr.Button("▶️ تشغيل المحاكاة", variant="primary")
200
 
 
201
  controller_output = gr.Textbox(label="بيانات متحكم القيادة", interactive=False)
202
 
203
  with gr.Column(scale=3):
 
204
  dashboard_output = gr.Image(label="لوحة المعلومات الحية (Dashboard)", interactive=False)
205
 
206
+ # --- ربط الأحداث ---
207
+
208
+ # 1. عند تغيير النمو��ج في القائمة، قم بتحميله
209
+ model_selector.change(
210
+ fn=load_model_by_name,
211
+ inputs=[model_selector],
212
+ outputs=[model_load_status] # عرض حالة التحميل للمستخدم
213
+ )
214
+
215
+ # 2. عند الضغط على زر التشغيل، قم بتشغيل المحاكاة
216
  if available_models and available_scenarios:
217
  run_button.click(
218
  fn=run_simulation,
219
+ inputs=[scenario_selector],
220
  outputs=[dashboard_output, controller_output]
221
  )
222
  else:
223
  gr.Warning("لا يمكن العثور على نماذج أو سيناريوهات. يرجى التأكد من إعداد المجلدات بشكل صحيح.")
224
+
225
+ # تحميل النموذج الافتراضي عند بدء تشغيل الواجهة
226
+ demo.load(
227
+ fn=load_model_by_name,
228
+ inputs=[model_selector],
229
+ outputs=[model_load_status]
230
+ )
231
 
232
+ # --- الجزء السادس: إطلاق الواجهة ---
233
  if __name__ == "__main__":
234
+ demo.launch(debug=True)```