osamabyc86 commited on
Commit
7ca8135
·
verified ·
1 Parent(s): 70e8a9d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +818 -53
app.py CHANGED
@@ -1,57 +1,822 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  import gradio as gr
2
- from huggingface_hub import InferenceClient
3
- import subprocess
4
-
5
- # شغل main.py في الخلفية
6
- subprocess.Popen(["python", "main.py"])
7
-
8
- client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")
9
-
10
- def respond(
11
- message,
12
- history: list[tuple[str, str]],
13
- system_message,
14
- max_tokens,
15
- temperature,
16
- top_p,
17
- ):
18
- messages = [{"role": "system", "content": system_message}]
19
-
20
- for val in history:
21
- if val[0]:
22
- messages.append({"role": "user", "content": val[0]})
23
- if val[1]:
24
- messages.append({"role": "assistant", "content": val[1]})
25
-
26
- messages.append({"role": "user", "content": message})
27
-
28
- response = ""
29
- for message in client.chat_completion(
30
- messages,
31
- max_tokens=max_tokens,
32
- stream=True,
33
- temperature=temperature,
34
- top_p=top_p,
35
- ):
36
- token = message.choices[0].delta.content
37
- response += token
38
- yield response
39
-
40
- demo = gr.ChatInterface(
41
- respond,
42
- additional_inputs=[
43
- gr.Textbox(value="You are a friendly Chatbot.", label="System message"),
44
- gr.Slider(minimum=1, maximum=2048, value=512, step=1, label="Max new tokens"),
45
- gr.Slider(minimum=0.1, maximum=4.0, value=0.7, step=0.1, label="Temperature"),
46
- gr.Slider(
47
- minimum=0.1,
48
- maximum=1.0,
49
- value=0.95,
50
- step=0.05,
51
- label="Top-p (nucleus sampling)",
52
- ),
53
- ],
54
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  if __name__ == "__main__":
57
- demo.launch()
 
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ نظام توزيع المهام الذكي - الخادم المركزي على Hugging Face
5
+ يجمع بين واجهة Gradio وخادم التوزيع المركزي
6
+ """
7
+
8
+ import os
9
+ import sys
10
+ import time
11
+ import json
12
+ import logging
13
+ import threading
14
+ import random
15
+ import queue
16
+ from datetime import datetime
17
+ from typing import Dict, List, Optional, Any
18
+ from dataclasses import dataclass, field, asdict
19
+
20
  import gradio as gr
21
+ from flask import Flask, request, jsonify
22
+ from flask_cors import CORS
23
+ import requests
24
+
25
+ # ─────────────── إعداد السجلات ───────────────
26
+ logging.basicConfig(
27
+ level=logging.INFO,
28
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  )
30
+ logger = logging.getLogger("CentralServerHF")
31
+
32
+ # ─────────────── هياكل البيانات ───────────────
33
+ @dataclass
34
+ class NodeInfo:
35
+ """معلومات العقدة المتصلة"""
36
+ node_id: str
37
+ ip: str
38
+ port: int
39
+ url: str
40
+ capabilities: List[str]
41
+ cpu_usage: float = 0.0
42
+ memory_usage: float = 0.0
43
+ status: str = "online"
44
+ last_seen: datetime = field(default_factory=datetime.now)
45
+ success_rate: float = 1.0
46
+ response_time: float = 0.0
47
+ tasks_completed: int = 0
48
+ tasks_failed: int = 0
49
+ current_tasks: int = 0
50
+ weight: float = 1.0 # للأوزان الذكية
51
+
52
+ @property
53
+ def score(self) -> float:
54
+ """حساب درجة العقدة"""
55
+ health = 0.4 * (100 - (self.cpu_usage + self.memory_usage) / 2) / 100
56
+ performance = 0.3 * self.success_rate
57
+ availability = 0.2 * (1.0 - self.current_tasks / 5)
58
+ speed = 0.1 * max(0, 1 - self.response_time / 10)
59
+
60
+ return (health + performance + availability + speed) * self.weight
61
+
62
+ @dataclass
63
+ class TaskInfo:
64
+ """معلومات المهمة"""
65
+ task_id: str
66
+ task_type: str
67
+ params: Dict[str, Any]
68
+ sender: str
69
+ status: str = "pending" # pending, processing, completed, failed
70
+ assigned_to: Optional[str] = None
71
+ result: Optional[Any] = None
72
+ error: Optional[str] = None
73
+ created_at: datetime = field(default_factory=datetime.now)
74
+ started_at: Optional[datetime] = None
75
+ completed_at: Optional[datetime] = None
76
+ priority: int = 2 # 1=high, 2=medium, 3=low
77
+
78
+ # ─────────────── فئة الخادم المركزي ───────────────
79
+ class CentralServer:
80
+ """الخادم المركزي الذكي لتوزيع المهام"""
81
+
82
+ def __init__(self):
83
+ self.nodes: Dict[str, NodeInfo] = {}
84
+ self.tasks: Dict[str, TaskInfo] = {}
85
+ self.task_queue = queue.PriorityQueue()
86
+ self.lock = threading.RLock()
87
+ self.is_running = True
88
+
89
+ # إحصائيات النظام
90
+ self.metrics = {
91
+ "total_nodes": 0,
92
+ "online_nodes": 0,
93
+ "total_tasks": 0,
94
+ "completed_tasks": 0,
95
+ "failed_tasks": 0,
96
+ "avg_response_time": 0.0,
97
+ "system_uptime": time.time()
98
+ }
99
+
100
+ # بدء الخدمات الخلفية
101
+ self._start_background_services()
102
+
103
+ logger.info("🚀 بدء تشغيل الخادم المركزي على Hugging Face")
104
+
105
+ def _start_background_services(self):
106
+ """بدء الخدمات الخلفية"""
107
+ # خيط ��وزيع المهام
108
+ self.dispatcher = threading.Thread(target=self._dispatch_loop, daemon=True)
109
+ self.dispatcher.start()
110
+
111
+ # خيط فحص صحة العقد
112
+ self.health_checker = threading.Thread(target=self._health_check_loop, daemon=True)
113
+ self.health_checker.start()
114
+
115
+ # خيط محاكاة العقد (للتجربة)
116
+ self.simulator = threading.Thread(target=self._simulate_nodes, daemon=True)
117
+ self.simulator.start()
118
+
119
+ def register_node(self, node_data: Dict) -> Dict:
120
+ """تسجيل عقدة جديدة"""
121
+ with self.lock:
122
+ node_id = node_data.get('node_id', f"node_{len(self.nodes)+1}")
123
+
124
+ node = NodeInfo(
125
+ node_id=node_id,
126
+ ip=node_data.get('ip', '127.0.0.1'),
127
+ port=node_data.get('port', 0),
128
+ url=node_data.get('url', ''),
129
+ capabilities=node_data.get('capabilities', ['general']),
130
+ cpu_usage=node_data.get('cpu_usage', 0.0),
131
+ memory_usage=node_data.get('memory_usage', 0.0),
132
+ status='online'
133
+ )
134
+
135
+ self.nodes[node_id] = node
136
+ self.metrics["total_nodes"] = len(self.nodes)
137
+ self.metrics["online_nodes"] = len([n for n in self.nodes.values() if n.status == 'online'])
138
+
139
+ logger.info(f"✅ عقدة مسجلة: {node_id}")
140
+
141
+ return {
142
+ "status": "success",
143
+ "node_id": node_id,
144
+ "message": "تم التسجيل بنجاح",
145
+ "server_time": datetime.now().isoformat()
146
+ }
147
+
148
+ def update_node_status(self, node_id: str, metrics: Dict):
149
+ """تحديث حالة العقدة"""
150
+ with self.lock:
151
+ if node_id in self.nodes:
152
+ node = self.nodes[node_id]
153
+
154
+ if 'cpu_usage' in metrics:
155
+ node.cpu_usage = metrics['cpu_usage']
156
+ if 'memory_usage' in metrics:
157
+ node.memory_usage = metrics['memory_usage']
158
+ if 'current_tasks' in metrics:
159
+ node.current_tasks = metrics['current_tasks']
160
+ if 'status' in metrics:
161
+ node.status = metrics['status']
162
+
163
+ node.last_seen = datetime.now()
164
+
165
+ # تحديث معدل النجاح
166
+ total = node.tasks_completed + node.tasks_failed
167
+ if total > 0:
168
+ node.success_rate = node.tasks_completed / total
169
+
170
+ return {"status": "updated"}
171
+
172
+ return {"error": "العقدة غير موجودة"}
173
+
174
+ def submit_task(self, task_data: Dict) -> Dict:
175
+ """إرسال مهمة جديدة"""
176
+ task_id = task_data.get('task_id', f"task_{int(time.time())}_{random.randint(1000,9999)}")
177
+
178
+ task = TaskInfo(
179
+ task_id=task_id,
180
+ task_type=task_data.get('task_type', 'general'),
181
+ params=task_data.get('params', {}),
182
+ sender=task_data.get('sender', 'unknown'),
183
+ priority=task_data.get('priority', 2)
184
+ )
185
+
186
+ with self.lock:
187
+ self.tasks[task_id] = task
188
+ self.metrics["total_tasks"] = len(self.tasks)
189
+
190
+ # إضافة إلى قائمة الانتظار
191
+ self.task_queue.put((task.priority, task_id))
192
+
193
+ logger.info(f"📨 مهمة مستلمة: {task_id} ({task.task_type})")
194
+
195
+ return {
196
+ "status": "accepted",
197
+ "task_id": task_id,
198
+ "queue_position": self.task_queue.qsize(),
199
+ "estimated_wait": self.task_queue.qsize() * 2 # ثانيتين لكل مهمة
200
+ }
201
+
202
+ def _dispatch_loop(self):
203
+ """حلقة توزيع المهام"""
204
+ while self.is_running:
205
+ try:
206
+ # انتظار مهمة
207
+ priority, task_id = self.task_queue.get(timeout=1.0)
208
+
209
+ with self.lock:
210
+ task = self.tasks.get(task_id)
211
+ if not task or task.status != "pending":
212
+ continue
213
+
214
+ # إيجاد أفضل عقدة
215
+ best_node = self._select_best_node(task.task_type)
216
+
217
+ if best_node:
218
+ # تعيين المهمة
219
+ self._assign_task(task, best_node)
220
+ else:
221
+ # إعادة المحاولة
222
+ time.sleep(3)
223
+ self.task_queue.put((priority, task_id))
224
+
225
+ except queue.Empty:
226
+ continue
227
+ except Exception as e:
228
+ logger.error(f"❌ خطأ في التوزيع: {e}")
229
+ time.sleep(5)
230
+
231
+ def _select_best_node(self, task_type: str) -> Optional[NodeInfo]:
232
+ """اختيار أفضل عقدة للمهمة"""
233
+ with self.lock:
234
+ # فلترة العقد المتاحة
235
+ available = []
236
+ for node in self.nodes.values():
237
+ if node.status != 'online':
238
+ continue
239
+ if node.cpu_usage > 85 or node.memory_usage > 85:
240
+ continue
241
+ if node.current_tasks >= 3:
242
+ continue
243
+
244
+ # التحقق من القدرات
245
+ capabilities_needed = []
246
+ if task_type in ['matrix', 'fibonacci']:
247
+ capabilities_needed = ['cpu_intensive']
248
+ elif task_type in ['data', 'processing']:
249
+ capabilities_needed = ['memory']
250
+
251
+ if capabilities_needed:
252
+ if not any(cap in node.capabilities for cap in capabilities_needed):
253
+ continue
254
+
255
+ available.append(node)
256
+
257
+ if not available:
258
+ return None
259
+
260
+ # اختيار الأعلى درجة
261
+ return max(available, key=lambda n: n.score)
262
+
263
+ def _assign_task(self, task: TaskInfo, node: NodeInfo):
264
+ """تعيين مهمة لعقدة"""
265
+ try:
266
+ # تحديث حالة المهمة
267
+ with self.lock:
268
+ task.status = "processing"
269
+ task.assigned_to = node.node_id
270
+ task.started_at = datetime.now()
271
+ node.current_tasks += 1
272
+
273
+ logger.info(f"🎯 تعيين {task.task_id} → {node.node_id}")
274
+
275
+ # محاكاة التنفيذ
276
+ execution_time = self._simulate_task_execution(task, node)
277
+
278
+ # تحديث النتيجة
279
+ with self.lock:
280
+ task.status = "completed"
281
+ task.completed_at = datetime.now()
282
+ task.result = {
283
+ "executed_on": node.node_id,
284
+ "execution_time": execution_time,
285
+ "task_type": task.task_type,
286
+ "result": f"نتيجة محاكاة لـ {task.task_type}"
287
+ }
288
+
289
+ node.current_tasks -= 1
290
+ node.tasks_completed += 1
291
+ node.response_time = execution_time
292
+
293
+ self.metrics["completed_tasks"] += 1
294
+
295
+ logger.info(f"✅ مكتملة: {task.task_id} في {execution_time:.2f}s")
296
+
297
+ except Exception as e:
298
+ logger.error(f"❌ فشلت المهمة {task.task_id}: {e}")
299
+
300
+ with self.lock:
301
+ task.status = "failed"
302
+ task.error = str(e)
303
+ self.metrics["failed_tasks"] += 1
304
+
305
+ if node.node_id in self.nodes:
306
+ self.nodes[node.node_id].tasks_failed += 1
307
+ self.nodes[node.node_id].current_tasks -= 1
308
+
309
+ def _simulate_task_execution(self, task: TaskInfo, node: NodeInfo) -> float:
310
+ """محاكاة تنفيذ المهمة"""
311
+ # أوقات تنفيذ مختلفة حسب نوع المهمة
312
+ base_times = {
313
+ 'matrix': 1.5,
314
+ 'fibonacci': 0.8,
315
+ 'primes': 1.2,
316
+ 'data': 0.5,
317
+ 'image': 2.0,
318
+ 'general': 0.3
319
+ }
320
+
321
+ base_time = base_times.get(task.task_type, 0.5)
322
+
323
+ # تأثير حمل العقدة
324
+ load_factor = 1 + (node.cpu_usage + node.memory_usage) / 200
325
+
326
+ # تأثير حجم المهمة
327
+ size = task.params.get('size', 10) if isinstance(task.params, dict) else 10
328
+ size_factor = 1 + (size / 1000)
329
+
330
+ # وقت تنفيذ محاكي
331
+ execution_time = base_time * load_factor * size_factor
332
+
333
+ # محاكاة الانتظار
334
+ time.sleep(min(execution_time, 3.0))
335
+
336
+ return execution_time
337
+
338
+ def _health_check_loop(self):
339
+ """فحص صحة العقد"""
340
+ while self.is_running:
341
+ try:
342
+ with self.lock:
343
+ now = datetime.now()
344
+ for node in self.nodes.values():
345
+ # إذا مر أكثر من 2 دقيقة دون تحديث
346
+ if (now - node.last_seen).total_seconds() > 120:
347
+ node.status = "offline"
348
+
349
+ # تحديث الإحصائيات
350
+ self.metrics["online_nodes"] = len(
351
+ [n for n in self.nodes.values() if n.status == 'online']
352
+ )
353
+
354
+ time.sleep(30)
355
+
356
+ except Exception as e:
357
+ logger.error(f"❌ خطأ في فحص الصحة: {e}")
358
+ time.sleep(60)
359
+
360
+ def _simulate_nodes(self):
361
+ """محاكاة عقد افتراضية (للتجربة)"""
362
+ # إنشاء عقد افتراضية
363
+ virtual_nodes = [
364
+ {"id": "node_cpu1", "capabilities": ["cpu_intensive"], "cpu": 20, "memory": 40},
365
+ {"id": "node_mem1", "capabilities": ["memory"], "cpu": 30, "memory": 25},
366
+ {"id": "node_gpu1", "capabilities": ["gpu", "image"], "cpu": 25, "memory": 50},
367
+ {"id": "node_gen1", "capabilities": ["general"], "cpu": 15, "memory": 35}
368
+ ]
369
+
370
+ for vnode in virtual_nodes:
371
+ self.register_node({
372
+ "node_id": vnode["id"],
373
+ "ip": "192.168.1." + str(random.randint(100, 200)),
374
+ "port": random.randint(5000, 6000),
375
+ "url": f"http://192.168.1.{random.randint(100,200)}:{random.randint(5000,6000)}",
376
+ "capabilities": vnode["capabilities"],
377
+ "cpu_usage": vnode["cpu"],
378
+ "memory_usage": vnode["memory"]
379
+ })
380
+
381
+ # محاكاة تحديثات دورية
382
+ while self.is_running:
383
+ try:
384
+ with self.lock:
385
+ for node_id in list(self.nodes.keys())[:4]: # أول 4 عقد (الافتراضية)
386
+ if node_id in self.nodes:
387
+ node = self.nodes[node_id]
388
+ node.cpu_usage = max(5, min(80, node.cpu_usage + random.uniform(-5, 5)))
389
+ node.memory_usage = max(10, min(70, node.memory_usage + random.uniform(-3, 3)))
390
+ node.current_tasks = random.randint(0, 2)
391
+ node.last_seen = datetime.now()
392
+
393
+ time.sleep(10)
394
+
395
+ except Exception as e:
396
+ logger.error(f"❌ خطأ في محاكاة العقد: {e}")
397
+ time.sleep(30)
398
+
399
+ def get_system_overview(self) -> Dict:
400
+ """نظرة عامة على النظام"""
401
+ with self.lock:
402
+ now = datetime.now()
403
+
404
+ # حساب متوسط وقت الاستجابة
405
+ response_times = [n.response_time for n in self.nodes.values() if n.response_time > 0]
406
+ avg_response = sum(response_times) / len(response_times) if response_times else 0
407
+
408
+ # المهام الأخيرة
409
+ recent_tasks = list(self.tasks.values())[-10:] # آخر 10 مهام
410
+
411
+ return {
412
+ "metrics": {
413
+ **self.metrics,
414
+ "uptime": time.time() - self.metrics["system_uptime"],
415
+ "avg_response_time": avg_response,
416
+ "queue_size": self.task_queue.qsize(),
417
+ "timestamp": now.isoformat()
418
+ },
419
+ "nodes": [
420
+ {
421
+ "id": n.node_id,
422
+ "status": n.status,
423
+ "score": round(n.score, 3),
424
+ "cpu": n.cpu_usage,
425
+ "memory": n.memory_usage,
426
+ "tasks": n.current_tasks,
427
+ "success_rate": round(n.success_rate, 2),
428
+ "last_seen": (now - n.last_seen).total_seconds()
429
+ }
430
+ for n in self.nodes.values()
431
+ ],
432
+ "recent_tasks": [
433
+ {
434
+ "id": t.task_id,
435
+ "type": t.task_type,
436
+ "status": t.status,
437
+ "assigned_to": t.assigned_to,
438
+ "created": t.created_at.strftime("%H:%M:%S")
439
+ }
440
+ for t in recent_tasks
441
+ ]
442
+ }
443
+
444
+ # ─────────────── إنشاء الخادم المركزي ───────────────
445
+ central_server = CentralServer()
446
+
447
+ # ─────────────── دوال Gradio ───────────────
448
+ def get_system_status():
449
+ """الحصول على حالة النظام"""
450
+ overview = central_server.get_system_overview()
451
+
452
+ metrics = overview["metrics"]
453
+ nodes = overview["nodes"]
454
+ tasks = overview["recent_tasks"]
455
+
456
+ # تنسيق النص
457
+ status_text = f"""
458
+ # 🌐 الخادم المركزي لتوزيع المهام
459
+
460
+ ## 📊 إحصائيات النظام
461
+ - **الوقت:** {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
462
+ - **مدة التشغيل:** {metrics['uptime']/3600:.1f} ساعة
463
+ - **العقد الإجمالية:** {metrics['total_nodes']}
464
+ - **العقد النشطة:** {metrics['online_nodes']}
465
+ - **المهام الإجمالية:** {metrics['total_tasks']}
466
+ - **المهام المكتملة:** {metrics['completed_tasks']}
467
+ - **المهام الفاشلة:** {metrics['failed_tasks']}
468
+ - **متوسط وقت الاستجابة:** {metrics['avg_response_time']:.2f} ثا��ية
469
+ - **المهام في الانتظار:** {metrics['queue_size']}
470
+
471
+ ## 👥 العقد المتصلة ({len(nodes)})
472
+ """
473
+
474
+ for node in nodes:
475
+ status_emoji = "🟢" if node['status'] == 'online' else "🔴" if node['status'] == 'offline' else "🟡"
476
+ status_text += f"\n**{status_emoji} {node['id']}**"
477
+ status_text += f"\n - النقاط: {node['score']:.3f}"
478
+ status_text += f"\n - CPU: {node['cpu']:.1f}% | ذاكرة: {node['memory']:.1f}%"
479
+ status_text += f"\n - المهام النشطة: {node['tasks']}"
480
+ status_text += f"\n - معدل النجاح: {node['success_rate']*100:.1f}%"
481
+ status_text += f"\n - آخر ظهور: {node['last_seen']:.0f} ثانية مضت"
482
+
483
+ if tasks:
484
+ status_text += f"\n\n## 📋 آخر المهام ({len(tasks)})"
485
+ for task in tasks[-5:]: # آخر 5 مهام
486
+ status_emoji = "🟢" if task['status'] == 'completed' else "🟡" if task['status'] == 'processing' else "🔴"
487
+ status_text += f"\n{status_emoji} **{task['id']}** ({task['type']}) → {task['assigned_to'] or 'في الانتظار'}"
488
+
489
+ return status_text
490
+
491
+ def submit_task_ui(task_type, params_json):
492
+ """إرسال مهمة جديدة"""
493
+ try:
494
+ params = json.loads(params_json) if params_json else {}
495
+ except:
496
+ params = {"size": 10}
497
+
498
+ task_data = {
499
+ "task_type": task_type,
500
+ "params": params,
501
+ "sender": "gradio_ui",
502
+ "priority": 2
503
+ }
504
+
505
+ result = central_server.submit_task(task_data)
506
+
507
+ if "error" in result:
508
+ return f"## ❌ خطأ\n{result['error']}"
509
+
510
+ return f"""
511
+ ## ✅ تم قبول المهمة
512
+
513
+ ### 📝 معلومات المهمة
514
+ - **معرف المهمة:** {result['task_id']}
515
+ - **نوع المهمة:** {task_type}
516
+ - **الحالة:** في قائمة الانتظار
517
+ - **الموقع في الطابور:** {result['queue_position']}
518
+ - **الوقت المتوقع:** {result['estimated_wait']} ثانية
519
+ - **الوقت:** {datetime.now().strftime('%H:%M:%S')}
520
+
521
+ ### 📊 تتبع المهمة
522
+ سيتم تعيين المهمة لأفضل عقدة متاحة تلقائياً.
523
+ """
524
+
525
+ def get_node_details():
526
+ """الحصول على تفاصيل العقد"""
527
+ overview = central_server.get_system_overview()
528
+ nodes = overview["nodes"]
529
+
530
+ headers = ["العقدة", "الحالة", "النقاط", "CPU%", "الذاكرة%", "المهام", "معدل النجاح", "آخر ظهور"]
531
+ data = []
532
+
533
+ for node in nodes:
534
+ status_emoji = "🟢" if node['status'] == 'online' else "🔴"
535
+ data.append([
536
+ node['id'],
537
+ f"{status_emoji} {node['status']}",
538
+ f"{node['score']:.3f}",
539
+ f"{node['cpu']:.1f}",
540
+ f"{node['memory']:.1f}",
541
+ str(node['tasks']),
542
+ f"{node['success_rate']*100:.1f}%",
543
+ f"{node['last_seen']:.0f}s"
544
+ ])
545
+
546
+ return data
547
+
548
+ def simulate_new_node():
549
+ """محاكاة عقدة جديدة"""
550
+ node_id = f"node_{int(time.time())}"
551
+ caps = random.choice([['cpu_intensive'], ['memory'], ['general'], ['gpu', 'image']])
552
+
553
+ result = central_server.register_node({
554
+ "node_id": node_id,
555
+ "ip": f"10.0.0.{random.randint(1, 255)}",
556
+ "port": random.randint(5000, 6000),
557
+ "url": f"http://10.0.0.{random.randint(1,255)}:{random.randint(5000,6000)}",
558
+ "capabilities": caps,
559
+ "cpu_usage": random.uniform(10, 40),
560
+ "memory_usage": random.uniform(20, 60)
561
+ })
562
+
563
+ return f"## 🆕 عقدة محاكاة\n**{node_id}** - {', '.join(caps)}\n\nتم التسجيل بنجاح!"
564
+
565
+ def simulate_task_load(count: int):
566
+ """محاكاة حمل مهام"""
567
+ task_types = ['matrix', 'fibonacci', 'primes', 'data', 'image', 'general']
568
+
569
+ for i in range(min(count, 10)): # حد أقصى 10 مهام
570
+ task_type = random.choice(task_types)
571
+ central_server.submit_task({
572
+ "task_type": task_type,
573
+ "params": {"size": random.randint(10, 1000)},
574
+ "sender": "simulation",
575
+ "priority": random.randint(1, 3)
576
+ })
577
+ time.sleep(0.1)
578
+
579
+ return f"## 📨 محاكاة حمل\nتم إرسال {min(count, 10)} مهام عشوائية!"
580
+
581
+ # ─────────────── واجهة Gradio ───────────────
582
+ def create_interface():
583
+ """إنشاء واجهة Gradio"""
584
+
585
+ with gr.Blocks(
586
+ title="الخادم المركزي لتوزيع المهام",
587
+ theme=gr.themes.Soft(primary_hue="blue", secondary_hue="teal")
588
+ ) as demo:
589
+ gr.Markdown("# 🌐 الخادم المركزي الذكي لتوزيع المهام")
590
+ gr.Markdown("### نسخة Hugging Face Spaces - خادم حقيقي")
591
+
592
+ with gr.Tabs():
593
+ # تبويب حالة النظام
594
+ with gr.TabItem("📊 لوحة التحكم"):
595
+ status_output = gr.Markdown()
596
+ refresh_btn = gr.Button("🔄 تحديث الحالة", variant="primary")
597
+
598
+ refresh_btn.click(get_system_status, outputs=status_output)
599
+ demo.load(get_system_status, outputs=status_output)
600
+
601
+ # تبويب إرسال المهام
602
+ with gr.TabItem("🚀 إرسال المهام"):
603
+ with gr.Row():
604
+ with gr.Column():
605
+ gr.Markdown("### إرسال مهمة جديدة")
606
+
607
+ task_type = gr.Dropdown(
608
+ choices=[
609
+ ("ضرب المصفوفات (CPU)", "matrix"),
610
+ ("متسلسلة فيبوناتشي", "fibonacci"),
611
+ ("الأعداد الأولية", "primes"),
612
+ ("معالجة البيانات", "data"),
613
+ ("محاكاة معالجة الصور", "image"),
614
+ ("مهمة عامة", "general")
615
+ ],
616
+ label="نوع المهمة",
617
+ value="matrix"
618
+ )
619
+
620
+ params_input = gr.Textbox(
621
+ label="معاملات المهمة (JSON)",
622
+ value='{"size": 100}',
623
+ placeholder='{"size": 100} أو {"limit": 1000}'
624
+ )
625
+
626
+ submit_btn = gr.Button("📨 إرسال المهمة", variant="primary")
627
+
628
+ with gr.Column():
629
+ gr.Markdown("### نتيجة الإرسال")
630
+ task_result = gr.Markdown()
631
+
632
+ submit_btn.click(submit_task_ui, [task_type, params_input], task_result)
633
+
634
+ # تبويب العقد
635
+ with gr.TabItem("👥 إدارة العقد"):
636
+ gr.Markdown("### العقد المتصلة")
637
+ nodes_table = gr.Dataframe(
638
+ headers=["العقدة", "الحالة", "النقاط", "CPU%", "الذاكرة%", "المهام", "معدل النجاح", "آخر ظهور"],
639
+ interactive=False,
640
+ datatype=["str", "str", "str", "str", "str", "str", "str", "str"]
641
+ )
642
+
643
+ with gr.Row():
644
+ refresh_nodes = gr.Button("🔄 تحديث قائمة العقد")
645
+ sim_node = gr.Button("➕ محاكاة عقدة جديدة")
646
+ sim_tasks = gr.Button("📨 محاكاة حمل مهام")
647
+ task_count = gr.Slider(1, 10, value=3, label="عدد المهام")
648
+
649
+ sim_result = gr.Markdown()
650
+
651
+ refresh_nodes.click(get_node_details, outputs=nodes_table)
652
+ sim_node.click(simulate_new_node, outputs=sim_result)
653
+ sim_tasks.click(simulate_task_load, task_count, sim_result)
654
+ demo.load(get_node_details, outputs=nodes_table)
655
+
656
+ # تبويب المعلومات
657
+ with gr.TabItem("ℹ️ معلومات النظام"):
658
+ gr.Markdown("""
659
+ ## 📖 عن الخادم المركزي
660
+
661
+ هذا تطبيق **خادم مركزي حقيقي** يعمل على Hugging Face Spaces.
662
+
663
+ ### ✨ المميزات:
664
+ - **توزيع ذكي للمهام** على أفضل عقدة متاحة
665
+ - **مراقبة في الوقت الفعلي** لجميع العقد
666
+ - **محاكاة متقدمة** للعقد والمهام
667
+ - **إحصائيات مفصلة** عن أداء النظام
668
+ - **واجهة تحكم كاملة** عبر Gradio
669
+
670
+ ### 🏗️ كيفية العمل:
671
+ 1. **العقد تتصل** بالخادم وتسجل نفسها
672
+ 2. **المهام ترسل** للخادم المركزي
673
+ 3. **الخادم يختار** أفضل عقدة بناءً على:
674
+ - استخدام CPU والذاكرة
675
+ - معدل النجاح السابق
676
+ - عدد المهام النشطة
677
+ - وقت الاستجابة
678
+ 4. **المهام تنفذ** على العقد المختارة
679
+ 5. **النتائج ترجع** للخادم
680
+
681
+ ### 🌐 API المتاح:
682
+ يمكن للعقد الحقيقية الاتصال عبر:
683
+ - `POST /register` - تسجيل عقدة
684
+ - `POST /task/submit` - إرسال مهمة
685
+ - `POST /status/update` - تحديث حالة
686
+ - `GET /nodes` - قائمة العقد
687
+ - `GET /tasks` - قائمة المهام
688
+
689
+ ### 🔧 التقنيات:
690
+ - Python 3 مع معالجة متعددة الخيوط
691
+ - Gradio للواجهة الأمامية
692
+ - خوارزميات توزيع ذكية
693
+ - نظام محاكاة متكامل
694
+ """)
695
+
696
+ gr.Markdown("---\n*الخادم المركزي لتوزيع المهام الذكي - الإصدار 3.0.0*")
697
+
698
+ return demo
699
+
700
+ # ─────────────── API Flask (للعقد الحقيقية) ───────────────
701
+ flask_app = Flask(__name__)
702
+ CORS(flask_app)
703
+
704
+ @flask_app.route('/')
705
+ def api_home():
706
+ return jsonify({
707
+ "message": "الخادم المركزي لتوزيع المهام",
708
+ "version": "3.0.0",
709
+ "status": "running",
710
+ "gradio_url": "https://huggingface.co/spaces/your-username/your-space"
711
+ })
712
+
713
+ @flask_app.route('/register', methods=['POST'])
714
+ def api_register():
715
+ try:
716
+ data = request.get_json()
717
+ result = central_server.register_node(data)
718
+ return jsonify(result)
719
+ except Exception as e:
720
+ return jsonify({"error": str(e)}), 500
721
+
722
+ @flask_app.route('/task/submit', methods=['POST'])
723
+ def api_submit_task():
724
+ try:
725
+ data = request.get_json()
726
+ result = central_server.submit_task(data)
727
+ return jsonify(result)
728
+ except Exception as e:
729
+ return jsonify({"error": str(e)}), 500
730
+
731
+ @flask_app.route('/status/update', methods=['POST'])
732
+ def api_update_status():
733
+ try:
734
+ data = request.get_json()
735
+ node_id = data.get('node_id')
736
+ if not node_id:
737
+ return jsonify({"error": "معرف العقدة مطلوب"}), 400
738
+
739
+ result = central_server.update_node_status(node_id, data)
740
+ return jsonify(result)
741
+ except Exception as e:
742
+ return jsonify({"error": str(e)}), 500
743
+
744
+ @flask_app.route('/nodes', methods=['GET'])
745
+ def api_get_nodes():
746
+ try:
747
+ overview = central_server.get_system_overview()
748
+ return jsonify({
749
+ "status": "success",
750
+ "count": len(overview["nodes"]),
751
+ "nodes": overview["nodes"]
752
+ })
753
+ except Exception as e:
754
+ return jsonify({"error": str(e)}), 500
755
+
756
+ @flask_app.route('/tasks', methods=['GET'])
757
+ def api_get_tasks():
758
+ try:
759
+ with central_server.lock:
760
+ tasks = list(central_server.tasks.values())[-50:]
761
+ tasks_data = []
762
+ for task in tasks:
763
+ task_dict = asdict(task)
764
+ for field in ["created_at", "started_at", "completed_at"]:
765
+ if task_dict[field]:
766
+ task_dict[field] = task_dict[field].isoformat()
767
+ tasks_data.append(task_dict)
768
+
769
+ return jsonify({
770
+ "status": "success",
771
+ "count": len(tasks_data),
772
+ "tasks": tasks_data
773
+ })
774
+ except Exception as e:
775
+ return jsonify({"error": str(e)}), 500
776
+
777
+ @flask_app.route('/stats', methods=['GET'])
778
+ def api_get_stats():
779
+ try:
780
+ overview = central_server.get_system_overview()
781
+ return jsonify({
782
+ "status": "success",
783
+ "stats": overview["metrics"]
784
+ })
785
+ except Exception as e:
786
+ return jsonify({"error": str(e)}), 500
787
+
788
+ # ─────────────── بدء Flask في خيط منفصل ───────────────
789
+ def start_flask_server():
790
+ """بدء خادم Flask للعقد الحقيقية"""
791
+ port = 7861 # منفذ مختلف عن Gradio
792
+ flask_app.run(
793
+ host="0.0.0.0",
794
+ port=port,
795
+ debug=False,
796
+ threaded=True,
797
+ use_reloader=False
798
+ )
799
+
800
+ # ─────────────── الدالة الرئيسية ───────────────
801
+ def main():
802
+ """الدالة الرئيسية"""
803
+ logger.info("🚀 بدء تشغيل تطبيق Hugging Face كخادم مركزي")
804
+
805
+ # بدء خادم Flask للAPI في خيط منفصل
806
+ flask_thread = threading.Thread(target=start_flask_server, daemon=True)
807
+ flask_thread.start()
808
+ logger.info("✅ بدء خادم Flask API على المنفذ 7861")
809
+
810
+ # إنشاء واجهة Gradio
811
+ demo = create_interface()
812
+
813
+ # تشغيل Gradio
814
+ demo.launch(
815
+ server_name="0.0.0.0",
816
+ server_port=7860,
817
+ share=False,
818
+ debug=False
819
+ )
820
 
821
  if __name__ == "__main__":
822
+ main()