mohammed-aljafry commited on
Commit
1049992
·
verified ·
1 Parent(s): 4819bb6

Upload app.py with huggingface_hub

Browse files
Files changed (1) hide show
  1. app.py +238 -0
app.py ADDED
@@ -0,0 +1,238 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app.py - الكود النهائي المعدل ليتوافق مع بنية measurements.json الحقيقية
2
+
3
+ import os
4
+ import json
5
+ import gradio as gr
6
+ import base64
7
+ from PIL import Image
8
+ import io
9
+ import requests
10
+
11
+ # ==============================================================================
12
+ # 1. إعدادات الـ API
13
+ # ==============================================================================
14
+ API_URL_BASE = "https://BaseerAI-baseer-server.hf.space"
15
+ API_START_SESSION_URL = f"{API_URL_BASE}/start_session"
16
+ API_RUN_STEP_URL = f"{API_URL_BASE}/run_step"
17
+ API_END_SESSION_URL = f"{API_URL_BASE}/end_session"
18
+
19
+ EXAMPLES_DIR = "examples"
20
+
21
+ # ==============================================================================
22
+ # 2. الدوال المساعدة والدوال التي تتصل بالـ API
23
+ # ==============================================================================
24
+
25
+ def image_to_base64(pil_image):
26
+ buffered = io.BytesIO()
27
+ pil_image.save(buffered, format="JPEG")
28
+ return base64.b64encode(buffered.getvalue()).decode('utf-8')
29
+
30
+ def base64_to_image(b64_string):
31
+ img_data = base64.b64decode(b64_string)
32
+ return Image.open(io.BytesIO(img_data))
33
+
34
+ def start_new_session():
35
+ """يبدأ جلسة جديدة على الخادم ويعيد معرف الجلسة وأمر إظهار الواجهة."""
36
+ print("Requesting to start a new session...")
37
+ try:
38
+ response = requests.post(API_START_SESSION_URL, timeout=30)
39
+ response.raise_for_status()
40
+ session_data = response.json()
41
+ session_id = session_data.get("session_id")
42
+ if not session_id:
43
+ raise gr.Error("لم يتمكن الخادم من بدء جلسة جديدة.")
44
+
45
+ status_message = f"✅ تم بدء جلسة جديدة بنجاح. أنت الآن متصل بالخادم."
46
+ print(f"Session started successfully: {session_id}")
47
+ return session_id, status_message, gr.update(visible=True)
48
+ except requests.exceptions.RequestException as e:
49
+ error_message = f"فشل الاتصال بخادم الـ API: {e}"
50
+ print(error_message)
51
+ raise gr.Error(error_message)
52
+
53
+ def handle_end_session(session_id):
54
+ """ينهي الجلسة الحالية على الخادم."""
55
+ if not session_id:
56
+ return "لا توجد جلسة نشطة لإنهائها.", None, gr.update(visible=False)
57
+
58
+ print(f"Requesting to end session: {session_id}")
59
+ try:
60
+ response = requests.post(f"{API_END_SESSION_URL}?session_id={session_id}", timeout=30)
61
+ response.raise_for_status()
62
+
63
+ status_message = f"🔌 تم إنهاء الجلسة بنجاح. انقطع الاتصال بالخادم."
64
+ print(status_message)
65
+ return status_message, None, gr.update(visible=False)
66
+ except requests.exceptions.RequestException as e:
67
+ error_message = f"حدث خطأ أثناء إنهاء الجلسة: {e}"
68
+ print(error_message)
69
+ raise gr.Error(error_message)
70
+
71
+ # --- [تم تعديل هذه الدالة] ---
72
+ def run_single_frame_via_api(session_id, rgb_image_path, measurements_path):
73
+ if not session_id:
74
+ raise gr.Error("لا توجد جلسة نشطة. يرجى بدء جلسة جديدة أولاً.")
75
+ if not (rgb_image_path and measurements_path):
76
+ raise gr.Error("الرجاء توفير الصورة الأمامية وملف القياسات على الأقل.")
77
+ try:
78
+ rgb_image_pil = Image.open(rgb_image_path).convert("RGB")
79
+ with open(measurements_path, 'r') as f:
80
+ measurements_dict = json.load(f)
81
+ image_b64 = image_to_base64(rgb_image_pil)
82
+
83
+ # --- [التعديل الرئيسي هنا] ---
84
+ # بناء الحمولة (Payload) بناءً على بنية الملف الحقيقية
85
+ payload = {
86
+ "session_id": session_id,
87
+ "image_b64": image_b64,
88
+ "measurements": {
89
+ "pos_global": measurements_dict.get('pos_global', [0.0, 0.0]),
90
+ "theta": measurements_dict.get('theta', 0.0),
91
+ "speed": measurements_dict.get('speed', 0.0),
92
+ "target_point": measurements_dict.get('target_point', [0.0, 100.0])
93
+ }
94
+ }
95
+
96
+ print(f"Sending run_step request for session: {session_id}")
97
+ response = requests.post(API_RUN_STEP_URL, json=payload, timeout=60)
98
+ response.raise_for_status()
99
+ api_result = response.json()
100
+ dashboard_b64 = api_result.get("dashboard_b64")
101
+ control_commands = api_result.get("control_commands", {})
102
+ if not dashboard_b64:
103
+ raise gr.Error("لم يتم إرجاع صورة لوحة التحكم من الـ API.")
104
+ output_image = base64_to_image(dashboard_b64)
105
+ return output_image, control_commands
106
+ except requests.exceptions.RequestException as e:
107
+ raise gr.Error(f"حدث خطأ أثناء الاتصال بالـ API: {e}")
108
+ except Exception as e:
109
+ raise gr.Error(f"حدث خطأ غير متوقع: {e}")
110
+
111
+ # ==============================================================================
112
+ # 4. تعريف واجهة Gradio
113
+ # ==============================================================================
114
+
115
+ with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue", secondary_hue="sky"), css=".gradio-container {max-width: 100% !important;}") as demo:
116
+ session_id_state = gr.State(value=None)
117
+
118
+ gr.Markdown("# 🚗 واجهة التحكم لنظام Baseer للقيادة الذاتية")
119
+ gr.Markdown("هذه الواجهة تعمل كـ **عميل (Client)** يتصل بـ **[Baseer Self-Driving API](https://huggingface.co/spaces/BaseerAI/baseer-server)** لمعالجة البيانات.")
120
+
121
+ gr.Markdown("---")
122
+
123
+ with gr.Group():
124
+ gr.Markdown("## ⚙️ التحكم بالجلسة")
125
+ with gr.Row():
126
+ start_session_button = gr.Button("🟢 بدء جلسة جديدة", variant="primary")
127
+ end_session_button = gr.Button("🔴 إنهاء الجلسة الحالية")
128
+ status_textbox = gr.Textbox(label="حالة الجلسة", interactive=False, value="في انتظار بدء الجلسة...")
129
+
130
+ gr.Markdown("")
131
+
132
+ with gr.Group(visible=False) as main_controls_group:
133
+ with gr.Row():
134
+ # -- العمود الأيسر: الإعدادات والمدخلات --
135
+ with gr.Column(scale=2):
136
+ with gr.Group():
137
+ gr.Markdown("### 🗂️ ارفع ملفات السيناريو")
138
+ api_rgb_image_path = gr.Image(type="filepath", label="صورة الكاميرا الأمامية (RGB)")
139
+ api_measurements_path = gr.File(label="ملف القياسات (JSON)", type="filepath")
140
+
141
+ # --- [تم حذف gr.JSON من هنا] ---
142
+
143
+ api_run_button = gr.Button("🚀 أرسل البيانات للمعالجة", variant="primary")
144
+
145
+ gr.Markdown("")
146
+
147
+ # ... (داخل with gr.Group(visible=False) as main_controls_group:)
148
+ with gr.Group():
149
+ gr.Markdown("### ✨ أمثلة جاهزة")
150
+
151
+ # التحقق من وجود مجلد الأمثلة لتجنب الأخطاء
152
+ if os.path.isdir(EXAMPLES_DIR) and \
153
+ os.path.exists(os.path.join(EXAMPLES_DIR, "sample1", "measurements.json")) and \
154
+ os.path.exists(os.path.join(EXAMPLES_DIR, "sample2", "measurements.json")):
155
+
156
+ # قراءة بيانات المثال الأول
157
+ with open(os.path.join(EXAMPLES_DIR, "sample1", "measurements.json"), 'r') as f:
158
+ data1 = json.load(f)
159
+
160
+ # قراءة بيانات المثال الثاني
161
+ with open(os.path.join(EXAMPLES_DIR, "sample2", "measurements.json"), 'r') as f:
162
+ data2 = json.load(f)
163
+
164
+ # --- [تعديل] 1: إنشاء مكونات جديدة لكل البيانات المستخدمة ---
165
+ # سيتم استخدام عناوينها كعناوين للأعمدة في الجدول
166
+ with gr.Column(visible=False):
167
+ example_speed = gr.Textbox(label="السرعة (m/s)")
168
+ example_theta = gr.Textbox(label="الاتجاه (Theta)")
169
+ example_pos = gr.Textbox(label="الموقع العام")
170
+ example_target = gr.Textbox(label="النقطة المستهدفة")
171
+
172
+ gr.Examples(
173
+ examples=[
174
+ # --- [تعديل] 2: بناء البيانات للأعمدة الجديدة ---
175
+ [
176
+ # المدخلات الأساسية
177
+ os.path.join(EXAMPLES_DIR, "sample1", "rgb.jpg"),
178
+ os.path.join(EXAMPLES_DIR, "sample1", "measurements.json"),
179
+ # البيانات للعرض فقط
180
+ f"{data1.get('speed', 0.0):.2f}",
181
+ f"{data1.get('theta', 0.0):.2f}",
182
+ str(data1.get('pos_global', 'N/A')),
183
+ str(data1.get('target_point', 'N/A'))
184
+ ],
185
+ [
186
+ # المدخلات الأساسية
187
+ os.path.join(EXAMPLES_DIR, "sample2", "rgb.jpg"),
188
+ os.path.join(EXAMPLES_DIR, "sample2", "measurements.json"),
189
+ # البيانات للعرض فقط
190
+ f"{data2.get('speed', 0.0):.2f}",
191
+ f"{data2.get('theta', 0.0):.2f}",
192
+ str(data2.get('pos_global', 'N/A')),
193
+ str(data2.get('target_point', 'N/A'))
194
+ ]
195
+ ],
196
+ # --- [تعديل] 3: تحديث المدخلات لتشمل كل الأعمدة ---
197
+ inputs=[
198
+ api_rgb_image_path,
199
+ api_measurements_path,
200
+ example_speed,
201
+ example_theta,
202
+ example_pos,
203
+ example_target
204
+ ],
205
+ label="اختر سيناريو اختبار",
206
+ )
207
+ else:
208
+ gr.Markdown("لم يتم العثور على مجلد الأمثلة (`examples`) أو محتوياته.")
209
+
210
+ # -- العمود الأيمن: المخرجات --
211
+ with gr.Column(scale=3):
212
+ with gr.Group():
213
+ gr.Markdown("### 📊 النتائج من الخادم")
214
+ api_output_image = gr.Image(label="لوحة التحكم المرئية (من الـ API)", type="pil", interactive=False, height=600)
215
+ api_control_json = gr.JSON(label="أوامر التحكم (من الـ API)")
216
+
217
+ # --- ربط منطق الواجهة ---
218
+ start_session_button.click(
219
+ fn=start_new_session,
220
+ inputs=None,
221
+ outputs=[session_id_state, status_textbox, main_controls_group]
222
+ )
223
+
224
+ end_session_button.click(
225
+ fn=handle_end_session,
226
+ inputs=[session_id_state],
227
+ outputs=[status_textbox, session_id_state, main_controls_group]
228
+ )
229
+
230
+ # --- [تم تعديل هذا الجزء] ---
231
+ api_run_button.click(
232
+ fn=run_single_frame_via_api,
233
+ inputs=[session_id_state, api_rgb_image_path, api_measurements_path], # تم حذف target_point_list
234
+ outputs=[api_output_image, api_control_json],
235
+ )
236
+
237
+ if __name__ == "__main__":
238
+ demo.queue().launch(debug=True)