|
|
import gradio as gr |
|
|
import pandas as pd |
|
|
import plotly.graph_objects as go |
|
|
import plotly.express as px |
|
|
from datetime import datetime, timedelta |
|
|
import json |
|
|
import os |
|
|
from typing import Dict, List, Any |
|
|
from chicken_ai import AdvancedChickenAI |
|
|
|
|
|
class AdminPanel: |
|
|
def __init__(self): |
|
|
self.ai = AdvancedChickenAI() |
|
|
self.data_dir = "/home/ubuntu/chicken_assistant/admin_data" |
|
|
self.ensure_data_directory() |
|
|
|
|
|
def ensure_data_directory(self): |
|
|
"""التأكد من وجود مجلد البيانات""" |
|
|
os.makedirs(self.data_dir, exist_ok=True) |
|
|
|
|
|
|
|
|
default_files = { |
|
|
"users.json": [], |
|
|
"farm_settings.json": { |
|
|
"farm_name": "مزرعة الدجاج الذكية", |
|
|
"location": "", |
|
|
"capacity": 1000, |
|
|
"established_date": datetime.now().strftime("%Y-%m-%d") |
|
|
}, |
|
|
"alerts.json": [], |
|
|
"reports.json": [] |
|
|
} |
|
|
|
|
|
for filename, default_content in default_files.items(): |
|
|
filepath = os.path.join(self.data_dir, filename) |
|
|
if not os.path.exists(filepath): |
|
|
with open(filepath, 'w', encoding='utf-8') as f: |
|
|
json.dump(default_content, f, ensure_ascii=False, indent=2) |
|
|
|
|
|
def load_data(self, filename: str) -> Any: |
|
|
"""تحميل البيانات من ملف""" |
|
|
filepath = os.path.join(self.data_dir, filename) |
|
|
try: |
|
|
with open(filepath, 'r', encoding='utf-8') as f: |
|
|
return json.load(f) |
|
|
except: |
|
|
return [] |
|
|
|
|
|
def save_data(self, filename: str, data: Any) -> bool: |
|
|
"""حفظ البيانات في ملف""" |
|
|
filepath = os.path.join(self.data_dir, filename) |
|
|
try: |
|
|
with open(filepath, 'w', encoding='utf-8') as f: |
|
|
json.dump(data, f, ensure_ascii=False, indent=2) |
|
|
return True |
|
|
except: |
|
|
return False |
|
|
|
|
|
def add_disease(self, name: str, symptoms: str, treatment: str, prevention: str, hygiene: str) -> str: |
|
|
"""إضافة مرض جديد""" |
|
|
if not all([name, symptoms, treatment, prevention, hygiene]): |
|
|
return "❌ يرجى ملء جميع الحقول المطلوبة" |
|
|
|
|
|
|
|
|
symptoms_list = [s.strip() for s in symptoms.split(',')] |
|
|
weights = {symptom: 0.8 for symptom in symptoms_list} |
|
|
|
|
|
self.ai.diseases_db[name] = { |
|
|
"symptoms": symptoms_list, |
|
|
"probability_weights": weights, |
|
|
"treatment": treatment, |
|
|
"prevention": prevention, |
|
|
"hygiene": hygiene |
|
|
} |
|
|
|
|
|
|
|
|
custom_diseases = self.load_data("custom_diseases.json") |
|
|
custom_diseases[name] = self.ai.diseases_db[name] |
|
|
self.save_data("custom_diseases.json", custom_diseases) |
|
|
|
|
|
return f"✅ تم إضافة المرض '{name}' بنجاح!" |
|
|
|
|
|
def add_breed(self, name: str, breed_type: str, egg_production: str, characteristics: str, immunity: str) -> str: |
|
|
"""إضافة سلالة جديدة""" |
|
|
if not all([name, breed_type, characteristics, immunity]): |
|
|
return "❌ يرجى ملء جميع الحقول المطلوبة" |
|
|
|
|
|
breed_info = { |
|
|
"type": breed_type, |
|
|
"characteristics": characteristics, |
|
|
"immunity": immunity |
|
|
} |
|
|
|
|
|
if egg_production: |
|
|
breed_info["egg_production"] = egg_production |
|
|
breed_info["egg_color"] = "غير محدد" |
|
|
|
|
|
self.ai.breeds_db[name] = breed_info |
|
|
|
|
|
|
|
|
custom_breeds = self.load_data("custom_breeds.json") |
|
|
custom_breeds[name] = breed_info |
|
|
self.save_data("custom_breeds.json", custom_breeds) |
|
|
|
|
|
return f"✅ تم إضافة السلالة '{name}' بنجاح!" |
|
|
|
|
|
def generate_farm_report(self) -> str: |
|
|
"""إنشاء تقرير شامل للمزرعة""" |
|
|
|
|
|
production_file = "/home/ubuntu/chicken_assistant/production_data.json" |
|
|
if os.path.exists(production_file): |
|
|
with open(production_file, 'r', encoding='utf-8') as f: |
|
|
production_data = json.load(f) |
|
|
else: |
|
|
production_data = [] |
|
|
|
|
|
if not production_data: |
|
|
return "📊 لا توجد بيانات إنتاج متاحة لإنشاء التقرير" |
|
|
|
|
|
|
|
|
total_eggs = sum(record.get('eggs', 0) for record in production_data) |
|
|
total_feed = sum(record.get('feed', 0) for record in production_data) |
|
|
days_count = len(production_data) |
|
|
avg_eggs_per_day = total_eggs / days_count if days_count > 0 else 0 |
|
|
avg_feed_per_day = total_feed / days_count if days_count > 0 else 0 |
|
|
|
|
|
|
|
|
feed_conversion_ratio = total_feed / total_eggs if total_eggs > 0 else 0 |
|
|
|
|
|
|
|
|
recent_data = production_data[-7:] if len(production_data) >= 7 else production_data |
|
|
recent_avg_eggs = sum(record.get('eggs', 0) for record in recent_data) / len(recent_data) |
|
|
|
|
|
trend = "📈 متزايد" if recent_avg_eggs > avg_eggs_per_day else "📉 متناقص" if recent_avg_eggs < avg_eggs_per_day else "➡️ مستقر" |
|
|
|
|
|
report = f""" |
|
|
# 📊 تقرير أداء المزرعة الشامل |
|
|
|
|
|
## 📈 إحصائيات الإنتاج العامة |
|
|
- **فترة التقرير:** {days_count} يوم |
|
|
- **إجمالي إنتاج البيض:** {total_eggs:,} بيضة |
|
|
- **متوسط الإنتاج اليومي:** {avg_eggs_per_day:.1f} بيضة/يوم |
|
|
- **إجمالي استهلاك العلف:** {total_feed:.1f} كجم |
|
|
- **متوسط استهلاك العلف:** {avg_feed_per_day:.1f} كجم/يوم |
|
|
|
|
|
## 🔄 كفاءة التحويل |
|
|
- **معدل تحويل العلف:** {feed_conversion_ratio:.2f} كجم علف/بيضة |
|
|
- **الاتجاه الحالي:** {trend} |
|
|
|
|
|
## 📊 تحليل الأداء |
|
|
- **أعلى إنتاج يومي:** {max(record.get('eggs', 0) for record in production_data)} بيضة |
|
|
- **أقل إنتاج يومي:** {min(record.get('eggs', 0) for record in production_data)} بيضة |
|
|
- **متوسط الأسبوع الأخير:** {recent_avg_eggs:.1f} بيضة/يوم |
|
|
|
|
|
## 💡 التوصيات |
|
|
""" |
|
|
|
|
|
|
|
|
if feed_conversion_ratio > 0.15: |
|
|
report += "- ⚠️ معدل تحويل العلف مرتفع، يُنصح بمراجعة جودة العلف ونوعه\n" |
|
|
|
|
|
if recent_avg_eggs < avg_eggs_per_day * 0.9: |
|
|
report += "- 📉 انخفاض في الإنتاج مؤخراً، يُنصح بفحص صحة القطيع\n" |
|
|
|
|
|
if avg_eggs_per_day < 0.7: |
|
|
report += "- 🔍 إنتاجية منخفضة، يُنصح بمراجعة التغذية والإضاءة\n" |
|
|
|
|
|
report += f"\n**تاريخ التقرير:** {datetime.now().strftime('%Y-%m-%d %H:%M')}" |
|
|
|
|
|
|
|
|
reports = self.load_data("reports.json") |
|
|
reports.append({ |
|
|
"date": datetime.now().isoformat(), |
|
|
"type": "farm_performance", |
|
|
"content": report |
|
|
}) |
|
|
self.save_data("reports.json", reports) |
|
|
|
|
|
return report |
|
|
|
|
|
def create_alert(self, alert_type: str, message: str, priority: str) -> str: |
|
|
"""إنشاء تنبيه جديد""" |
|
|
if not all([alert_type, message, priority]): |
|
|
return "❌ يرجى ملء جميع الحقول" |
|
|
|
|
|
alerts = self.load_data("alerts.json") |
|
|
|
|
|
new_alert = { |
|
|
"id": len(alerts) + 1, |
|
|
"type": alert_type, |
|
|
"message": message, |
|
|
"priority": priority, |
|
|
"created_at": datetime.now().isoformat(), |
|
|
"status": "active" |
|
|
} |
|
|
|
|
|
alerts.append(new_alert) |
|
|
self.save_data("alerts.json", alerts) |
|
|
|
|
|
priority_emoji = {"عالي": "🔴", "متوسط": "🟡", "منخفض": "🟢"} |
|
|
return f"✅ تم إنشاء التنبيه بنجاح!\n{priority_emoji.get(priority, '⚪')} {alert_type}: {message}" |
|
|
|
|
|
def get_active_alerts(self) -> str: |
|
|
"""الحصول على التنبيهات النشطة""" |
|
|
alerts = self.load_data("alerts.json") |
|
|
active_alerts = [alert for alert in alerts if alert.get("status") == "active"] |
|
|
|
|
|
if not active_alerts: |
|
|
return "✅ لا توجد تنبيهات نشطة حالياً" |
|
|
|
|
|
output = "## 🚨 التنبيهات النشطة\n\n" |
|
|
priority_emoji = {"عالي": "🔴", "متوسط": "🟡", "منخفض": "🟢"} |
|
|
|
|
|
for alert in sorted(active_alerts, key=lambda x: x.get("created_at", ""), reverse=True): |
|
|
emoji = priority_emoji.get(alert.get("priority", ""), "⚪") |
|
|
created_date = datetime.fromisoformat(alert.get("created_at", "")).strftime("%Y-%m-%d %H:%M") |
|
|
|
|
|
output += f"### {emoji} {alert.get('type', 'غير محدد')}\n" |
|
|
output += f"**الرسالة:** {alert.get('message', '')}\n" |
|
|
output += f"**الأولوية:** {alert.get('priority', 'غير محدد')}\n" |
|
|
output += f"**التاريخ:** {created_date}\n\n" |
|
|
output += "---\n\n" |
|
|
|
|
|
return output |
|
|
|
|
|
def update_farm_settings(self, farm_name: str, location: str, capacity: int) -> str: |
|
|
"""تحديث إعدادات المزرعة""" |
|
|
if not farm_name: |
|
|
return "❌ اسم المزرعة مطلوب" |
|
|
|
|
|
settings = self.load_data("farm_settings.json") |
|
|
settings.update({ |
|
|
"farm_name": farm_name, |
|
|
"location": location, |
|
|
"capacity": capacity, |
|
|
"last_updated": datetime.now().isoformat() |
|
|
}) |
|
|
|
|
|
if self.save_data("farm_settings.json", settings): |
|
|
return f"✅ تم تحديث إعدادات المزرعة بنجاح!\nالاسم: {farm_name}\nالموقع: {location}\nالسعة: {capacity:,} طائر" |
|
|
else: |
|
|
return "❌ حدث خطأ في حفظ الإعدادات" |
|
|
|
|
|
|
|
|
admin = AdminPanel() |
|
|
|
|
|
def create_admin_interface(): |
|
|
"""إنشاء واجهة لوحة الإدارة""" |
|
|
|
|
|
with gr.Blocks( |
|
|
title="🛠️ لوحة التحكم الإدارية - مساعد تربية الدجاج", |
|
|
theme=gr.themes.Soft( |
|
|
primary_hue="blue", |
|
|
secondary_hue="emerald", |
|
|
neutral_hue="slate", |
|
|
font=[gr.themes.GoogleFont("Cairo"), "Arial", "sans-serif"] |
|
|
), |
|
|
css=""" |
|
|
.admin-header { |
|
|
background: linear-gradient(135deg, #1e3a8a 0%, #3b82f6 100%); |
|
|
color: white; |
|
|
padding: 2rem; |
|
|
border-radius: 15px; |
|
|
margin-bottom: 2rem; |
|
|
text-align: center; |
|
|
} |
|
|
.admin-card { |
|
|
background: white; |
|
|
border-radius: 12px; |
|
|
padding: 1.5rem; |
|
|
box-shadow: 0 4px 15px rgba(0,0,0,0.1); |
|
|
border: 1px solid #e2e8f0; |
|
|
margin-bottom: 1rem; |
|
|
} |
|
|
.metric-grid { |
|
|
display: grid; |
|
|
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); |
|
|
gap: 1rem; |
|
|
margin: 1rem 0; |
|
|
} |
|
|
.metric-item { |
|
|
background: linear-gradient(135deg, #3b82f6 0%, #1e40af 100%); |
|
|
color: white; |
|
|
padding: 1rem; |
|
|
border-radius: 10px; |
|
|
text-align: center; |
|
|
} |
|
|
""" |
|
|
) as admin_app: |
|
|
|
|
|
|
|
|
gr.HTML(""" |
|
|
<div class="admin-header"> |
|
|
<h1 style="font-size: 2.5rem; margin-bottom: 0.5rem;">🛠️ لوحة التحكم الإدارية</h1> |
|
|
<p style="font-size: 1.2rem; opacity: 0.9;">إدارة شاملة لنظام مساعد تربية الدجاج الذكي</p> |
|
|
</div> |
|
|
""") |
|
|
|
|
|
with gr.Tabs() as admin_tabs: |
|
|
|
|
|
|
|
|
with gr.Tab("📝 إدارة المحتوى"): |
|
|
gr.HTML("<div class='admin-card'>") |
|
|
gr.Markdown("### 🦠 إضافة مرض جديد") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
disease_name = gr.Textbox(label="اسم المرض", placeholder="مثال: إنفلونزا الطيور") |
|
|
disease_symptoms = gr.Textbox( |
|
|
label="الأعراض (مفصولة بفواصل)", |
|
|
placeholder="خمول، حمى، صعوبة تنفس", |
|
|
lines=2 |
|
|
) |
|
|
disease_treatment = gr.Textbox( |
|
|
label="العلاج", |
|
|
placeholder="وصف العلاج المناسب...", |
|
|
lines=3 |
|
|
) |
|
|
|
|
|
with gr.Column(): |
|
|
disease_prevention = gr.Textbox( |
|
|
label="الوقاية", |
|
|
placeholder="إجراءات الوقاية...", |
|
|
lines=3 |
|
|
) |
|
|
disease_hygiene = gr.Textbox( |
|
|
label="النظافة", |
|
|
placeholder="إجراءات النظافة المطلوبة...", |
|
|
lines=3 |
|
|
) |
|
|
|
|
|
add_disease_btn = gr.Button("➕ إضافة المرض", variant="primary", size="lg") |
|
|
disease_status = gr.Markdown() |
|
|
|
|
|
gr.HTML("</div>") |
|
|
|
|
|
gr.HTML("<div class='admin-card'>") |
|
|
gr.Markdown("### 🐔 إضافة سلالة جديدة") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
breed_name = gr.Textbox(label="اسم السلالة", placeholder="مثال: براهما") |
|
|
breed_type = gr.Dropdown( |
|
|
label="نوع السلالة", |
|
|
choices=["بياض", "لاحم", "ثنائي الغرض", "زينة"], |
|
|
value="بياض" |
|
|
) |
|
|
breed_egg_production = gr.Textbox( |
|
|
label="إنتاج البيض (اختياري)", |
|
|
placeholder="200-250 بيضة/سنة" |
|
|
) |
|
|
|
|
|
with gr.Column(): |
|
|
breed_characteristics = gr.Textbox( |
|
|
label="الخصائص", |
|
|
placeholder="وصف خصائص السلالة...", |
|
|
lines=3 |
|
|
) |
|
|
breed_immunity = gr.Dropdown( |
|
|
label="مستوى المناعة", |
|
|
choices=["ممتازة", "جيدة", "متوسطة", "ضعيفة"], |
|
|
value="جيدة" |
|
|
) |
|
|
|
|
|
add_breed_btn = gr.Button("➕ إضافة السلالة", variant="primary", size="lg") |
|
|
breed_status = gr.Markdown() |
|
|
|
|
|
gr.HTML("</div>") |
|
|
|
|
|
|
|
|
with gr.Tab("📊 التقارير والإحصائيات"): |
|
|
gr.HTML("<div class='admin-card'>") |
|
|
gr.Markdown("### 📈 تقارير الأداء") |
|
|
|
|
|
generate_report_btn = gr.Button("📊 إنشاء تقرير شامل", variant="primary", size="lg") |
|
|
farm_report_output = gr.Markdown() |
|
|
|
|
|
gr.HTML("</div>") |
|
|
|
|
|
|
|
|
with gr.Tab("🚨 إدارة التنبيهات"): |
|
|
gr.HTML("<div class='admin-card'>") |
|
|
gr.Markdown("### ➕ إنشاء تنبيه جديد") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
alert_type = gr.Dropdown( |
|
|
label="نوع التنبيه", |
|
|
choices=["صحة القطيع", "نقص العلف", "انخفاض الإنتاج", "صيانة المعدات", "أخرى"], |
|
|
value="صحة القطيع" |
|
|
) |
|
|
alert_priority = gr.Dropdown( |
|
|
label="الأولوية", |
|
|
choices=["عالي", "متوسط", "منخفض"], |
|
|
value="متوسط" |
|
|
) |
|
|
|
|
|
with gr.Column(): |
|
|
alert_message = gr.Textbox( |
|
|
label="رسالة التنبيه", |
|
|
placeholder="وصف التنبيه...", |
|
|
lines=3 |
|
|
) |
|
|
|
|
|
create_alert_btn = gr.Button("🚨 إنشاء التنبيه", variant="primary", size="lg") |
|
|
alert_status = gr.Markdown() |
|
|
|
|
|
gr.HTML("</div>") |
|
|
|
|
|
gr.HTML("<div class='admin-card'>") |
|
|
gr.Markdown("### 📋 التنبيهات النشطة") |
|
|
|
|
|
refresh_alerts_btn = gr.Button("🔄 تحديث التنبيهات", variant="secondary") |
|
|
active_alerts_output = gr.Markdown() |
|
|
|
|
|
gr.HTML("</div>") |
|
|
|
|
|
|
|
|
with gr.Tab("⚙️ إعدادات المزرعة"): |
|
|
gr.HTML("<div class='admin-card'>") |
|
|
gr.Markdown("### 🏠 معلومات المزرعة") |
|
|
|
|
|
|
|
|
current_settings = admin.load_data("farm_settings.json") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
farm_name_input = gr.Textbox( |
|
|
label="اسم المزرعة", |
|
|
value=current_settings.get("farm_name", ""), |
|
|
placeholder="اسم المزرعة" |
|
|
) |
|
|
farm_location_input = gr.Textbox( |
|
|
label="الموقع", |
|
|
value=current_settings.get("location", ""), |
|
|
placeholder="المدينة، البلد" |
|
|
) |
|
|
|
|
|
with gr.Column(): |
|
|
farm_capacity_input = gr.Number( |
|
|
label="السعة (عدد الطيور)", |
|
|
value=current_settings.get("capacity", 1000), |
|
|
minimum=1 |
|
|
) |
|
|
|
|
|
update_settings_btn = gr.Button("💾 حفظ الإعدادات", variant="primary", size="lg") |
|
|
settings_status = gr.Markdown() |
|
|
|
|
|
gr.HTML("</div>") |
|
|
|
|
|
|
|
|
add_disease_btn.click( |
|
|
fn=admin.add_disease, |
|
|
inputs=[disease_name, disease_symptoms, disease_treatment, disease_prevention, disease_hygiene], |
|
|
outputs=[disease_status] |
|
|
) |
|
|
|
|
|
add_breed_btn.click( |
|
|
fn=admin.add_breed, |
|
|
inputs=[breed_name, breed_type, breed_egg_production, breed_characteristics, breed_immunity], |
|
|
outputs=[breed_status] |
|
|
) |
|
|
|
|
|
generate_report_btn.click( |
|
|
fn=admin.generate_farm_report, |
|
|
outputs=[farm_report_output] |
|
|
) |
|
|
|
|
|
create_alert_btn.click( |
|
|
fn=admin.create_alert, |
|
|
inputs=[alert_type, alert_message, alert_priority], |
|
|
outputs=[alert_status] |
|
|
) |
|
|
|
|
|
refresh_alerts_btn.click( |
|
|
fn=admin.get_active_alerts, |
|
|
outputs=[active_alerts_output] |
|
|
) |
|
|
|
|
|
update_settings_btn.click( |
|
|
fn=admin.update_farm_settings, |
|
|
inputs=[farm_name_input, farm_location_input, farm_capacity_input], |
|
|
outputs=[settings_status] |
|
|
) |
|
|
|
|
|
|
|
|
admin_app.load(fn=admin.get_active_alerts, outputs=[active_alerts_output]) |
|
|
|
|
|
return admin_app |
|
|
|
|
|
if __name__ == "__main__": |
|
|
admin_interface = create_admin_interface() |
|
|
admin_interface.launch( |
|
|
server_name="0.0.0.0", |
|
|
server_port=7861, |
|
|
share=False, |
|
|
show_error=True |
|
|
) |
|
|
|
|
|
|