Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import json | |
| import matplotlib.pyplot as plt # استيراد مكتبة Matplotlib لرسم المخططات | |
| import numpy as np # قد نحتاجه لبعض العمليات الحسابية البسيطة | |
| import matplotlib.font_manager as fm # استيراد font_manager للتحكم في الخطوط | |
| import arabic_reshaper # لاستعادة شكل الحروف العربية | |
| from bidi.algorithm import get_display # لضبط اتجاه النص RTL | |
| # استيراد الدالة الرئيسية لتقييم قائمة تشغيل YouTube من ملف main.py | |
| # تأكد أن ملف main.py موجود في نفس المجلد وأن النماذج (.pkl) متاحة له | |
| from main import evaluate_youtube_playlist_individually_same_method2 | |
| # ======================================================= | |
| # إعداد الخطوط لـ Matplotlib لدعم اللغة العربية | |
| # ======================================================= | |
| # يجب التأكد من تثبيت خط عربي في بيئة Docker الخاصة بـ Hugging Face Space. | |
| # مثال على التثبيت في Dockerfile: RUN apt-get update && apt-get install -y fonts-noto-arabic | |
| # سنبحث عن خط Noto Sans Arabic، وإذا لم نجده، سيظل Matplotlib يستخدم الخط الافتراضي | |
| font_path = None | |
| # البحث عن خط Noto Sans Arabic أو Tajawal (يمكنك تغيير هذا بناءً على الخط الذي تفضله وتثبته) | |
| for font in fm.findSystemFonts(fontpaths=None): | |
| if 'NotoSansArabic' in font or 'Tajawal' in font or 'Amiri' in font: | |
| font_path = font | |
| break | |
| if font_path: | |
| # إضافة الخط العربي إلى قائمة الخطوط الافتراضية لـ Matplotlib | |
| plt.rcParams['font.sans-serif'] = [fm.FontProperties(fname=font_path).get_name()] + plt.rcParams['font.sans-serif'] | |
| # تعطيل عرض علامة السالب كـ "صندوق" في بعض الخطوط | |
| plt.rcParams['axes.unicode_minus'] = False | |
| # تعيين عائلة الخط الافتراضية | |
| plt.rcParams['font.family'] = 'sans-serif' | |
| print(f"تم تعيين الخط العربي لـ Matplotlib: {font_path}") # لغرض التصحيح في السجلات | |
| else: | |
| print("تحذير: لم يتم العثور على خط عربي مناسب. قد لا يظهر النص العربي بشكل صحيح في المخطط.") | |
| gr.Warning("تحذير: لم يتم العثور على خط عربي مناسب. قد لا يظهر النص العربي بشكل صحيح في المخطط.") | |
| async def evaluate_playlist_local(youtube_url: str, max_comments_per_video: int = 50, max_workers: int = 3): | |
| """ | |
| تستدعي دالة تقييم قائمة تشغيل YouTube مباشرة من ملف main.py. | |
| وتعيد النتائج النصية مجمعة في صندوق واحد، بالإضافة إلى مخطط Matplotlib يوضح نسب التعليقات. | |
| """ | |
| error_message = "" | |
| # تهيئة المخرجات الافتراضية في حالة وجود خطأ أو عدم وجود رابط | |
| default_text_output = "الرجاء إدخال رابط صحيح وتشغيل التقييم." | |
| # إنشاء شكل Matplotlib فارغ لتجنب الأخطاء في حالة عدم وجود بيانات للمخطط | |
| default_plot = plt.figure() | |
| plt.close(default_plot) # إغلاق الشكل الافتراضي لمنع عرضه غير الضروري | |
| # التحقق من أن الرابط ليس فارغًا قبل المتابعة | |
| if not youtube_url: | |
| error_message = "الرجاء إدخال رابط قائمة تشغيل أو فيديو يوتيوب." | |
| gr.Warning(error_message) # عرض تحذير للمستخدم في واجهة Gradio | |
| return error_message, default_plot # إرجاع رسالة خطأ ومخطط فارغ | |
| try: | |
| # استدعاء الدالة الرئيسية لمعالجة قائمة التشغيل/الفيديو | |
| result = await evaluate_youtube_playlist_individually_same_method2( | |
| youtube_url=youtube_url, | |
| max_comments_per_video=max_comments_per_video, | |
| max_workers=max_workers | |
| ) | |
| # التحقق مما إذا كانت الدالة قد أعادت خطأ | |
| if "error" in result: | |
| error_message = f"خطأ في المعالجة: {result['error']}" | |
| gr.Error(error_message) # عرض الخطأ كرسالة خطأ حمراء في Gradio | |
| return error_message, default_plot # إرجاع رسالة الخطأ ومخطط فارغ | |
| # استخراج النتائج المطلوبة من كائن JSON المُعاد | |
| overall_quality = result.get("overall_quality", "غير متوفر") | |
| composite_quality = result.get("composite_quality", "غير متوفر") | |
| composite_score = result.get("composite_score", "غير متوفر") | |
| percent_good_videos = result.get("percent_good_videos", "غير متوفر") | |
| # التأكد من أن النسب عددية، وإلا سيتم تعيينها إلى 0.0 | |
| positive_ratio = result.get("positive_ratio", 0.0) | |
| negative_ratio = result.get("negative_ratio", 0.0) | |
| # ======================================================= | |
| # 1. إعداد النص الموحد ليتم عرضه في صندوق واحد (باستخدام Markdown للتنسيق) | |
| # ======================================================= | |
| formatted_output_text = f""" | |
| ## 📊 نتائج تقييم قائمة التشغيل: | |
| - **الجودة العامة:** **{overall_quality}** | |
| - **الجودة المركبة:** **{composite_quality}** | |
| - **النقاط المركبة:** **{composite_score} / 100** | |
| - **نسبة الفيديوهات الجيدة:** **{percent_good_videos}%** | |
| - **نسبة التعليقات الإيجابية:** **{positive_ratio}%** | |
| - **نسبة التعليقات السلبية:** **{negative_ratio}%** | |
| """ | |
| # ======================================================= | |
| # 2. رسم المخطط باستخدام Matplotlib (مخطط دائري) | |
| # ======================================================= | |
| # إنشاء شكل ومحاور للمخطط بحجم مناسب | |
| fig, ax = plt.subplots(figsize=(6, 4)) | |
| # النصوص العربية التي ستظهر على المخطط | |
| labels_arabic = ['إيجابية', 'سلبية'] | |
| # تطبيق arabic_reshaper و get_display على التسميات العربية | |
| # هذا هو الجزء الذي يحل مشكلة قلب النص وتقطيعه | |
| reshaped_labels = [get_display(arabic_reshaper.reshape(label)) for label in labels_arabic] | |
| sizes = [positive_ratio, negative_ratio] # قيم النسب المئوية | |
| colors = ['#4CAF50', '#F44336'] # ألوان الشرائح (أخضر للإيجابي، أحمر للسلبي) | |
| explode = (0.1, 0) # "تفجير" الشريحة الإيجابية قليلاً لإبرازها (اختياري) | |
| # رسم المخطط الدائري باستخدام التسميات المصححة | |
| ax.pie(sizes, explode=explode, labels=reshaped_labels, colors=colors, | |
| autopct='%1.1f%%', shadow=True, startangle=90, textprops={'fontsize': 12}) | |
| ax.axis('equal') # يضمن أن يكون المخطط دائريًا متناسبًا. | |
| # تطبيق arabic_reshaper و get_display على عنوان المخطط | |
| reshaped_title = get_display(arabic_reshaper.reshape('توزيع التعليقات')) | |
| ax.set_title(reshaped_title, fontsize=14, pad=20) | |
| # إغلاق الشكل لمنع Matplotlib من عرضه تلقائيًا في الخلفية، Gradio سيتولى العرض. | |
| plt.close(fig) | |
| # إرجاع النص المنسق والمخطط كناتجين للدالة | |
| return formatted_output_text, fig | |
| except Exception as e: | |
| # التقاط أي أخطاء غير متوقعة أثناء المعالجة | |
| error_message = f"حدث خطأ غير متوقع أثناء المعالجة: {e}" | |
| gr.Error(error_message) # عرض رسالة الخطأ للمستخدم | |
| return error_message, default_plot # إرجاع رسالة الخطأ ومخطط فارغ في حالة الفشل | |
| # بناء واجهة Gradio باستخدام gr.Blocks للتحكم في التخطيط | |
| with gr.Blocks(title="تقييم قائمة تشغيل يوتيوب") as demo: | |
| # عنوان ووصف الواجهة | |
| gr.Markdown("# 📊 تقييم جودة قائمة تشغيل يوتيوب") | |
| gr.Markdown("أدخل رابط قائمة تشغيل أو فيديو يوتيوب لتقييم جودتها بناءً على التحليلات والمشاعر.") | |
| # تقسيم الواجهة إلى صفين (Row) لأعمدة المدخلات والمخرجات | |
| with gr.Row(): | |
| # العمود الأول للمدخلات | |
| with gr.Column(scale=1): | |
| youtube_url_input = gr.Textbox(label="رابط قائمة تشغيل/فيديو يوتيوب", placeholder="الصق رابط يوتيوب هنا...", interactive=True) | |
| max_comments_input = gr.Slider(minimum=10, maximum=200, value=50, step=10, label="الحد الأقصى للتعليقات لكل فيديو", interactive=True) | |
| max_workers_input = gr.Slider(minimum=1, maximum=10, value=3, step=1, label="الحد الأقصى للعمال المتوازيين", interactive=True) | |
| submit_button = gr.Button("🚀 تقييم قائمة التشغيل", variant="primary") # زر الإرسال الرئيسي | |
| # العمود الثاني للمخرجات (بجعل scale=2 ليكون أكبر) | |
| with gr.Column(scale=2): | |
| # صندوق نصي واحد لعرض جميع النتائج النصية المنسقة | |
| output_text_box = gr.Markdown(label="النتائج النهائية للتقييم") | |
| # عنصر Gradio لعرض مخطط Matplotlib | |
| output_plot = gr.Plot(label="توزيع التعليقات (إيجابية مقابل سلبية)") | |
| # ربط زر الإرسال بالدالة evaluate_playlist_local | |
| # المدخلات هي عناصر واجهة المستخدم التي توفر البيانات للدالة | |
| # المخرجات هي عناصر واجهة المستخدم التي ستعرض النتائج من الدالة | |
| submit_button.click( | |
| evaluate_playlist_local, | |
| inputs=[youtube_url_input, max_comments_input, max_workers_input], | |
| outputs=[output_text_box, output_plot] | |
| ) | |
| # تشغيل واجهة Gradio | |
| demo.launch(debug=True) |