Update app.py
Browse files
app.py
CHANGED
@@ -1,117 +1,114 @@
|
|
1 |
-
|
2 |
import pandas as pd
|
|
|
3 |
from collections import Counter
|
4 |
from io import BytesIO
|
5 |
-
from docx import Document
|
6 |
-
import gradio as gr
|
7 |
-
import re
|
8 |
-
|
9 |
-
# تصنيف الهاشتاغات
|
10 |
-
HASHTAG_CATEGORIES = {
|
11 |
-
'رياضة': ['كرة_قدم', 'رياضة', 'دوري', 'كرة_سلة', 'تنس', 'سباحة', 'كرة_يد', 'أولمبياد', 'مباراة'],
|
12 |
-
'موسيقى': ['موسيقى', 'غناء', 'مطرب', 'أغنية', 'فن', 'مزيكا', 'غنائي', 'كليب', 'ألبوم'],
|
13 |
-
'تكنولوجيا': ['تكنولوجيا', 'تقنية', 'برمجة', 'ذكاء_اصطناعي', 'تطبيقات', 'هاتف', 'كمبيوتر', 'انترنت'],
|
14 |
-
}
|
15 |
-
|
16 |
-
def classify_hashtag(hashtag):
|
17 |
-
"""تصنيف الهاشتاغ حسب المجال"""
|
18 |
-
hashtag = hashtag.lower()
|
19 |
-
for category, keywords in HASHTAG_CATEGORIES.items():
|
20 |
-
if any(keyword in hashtag for keyword in keywords):
|
21 |
-
return category
|
22 |
-
return 'أخرى'
|
23 |
|
24 |
-
|
25 |
-
|
26 |
-
cleaned_title = re.sub(r'[^\u0600-\u06FF\s]', '', title)
|
27 |
-
words = cleaned_title.split()
|
28 |
-
return ', '.join([word for word in words if len(word) > 2][:5])
|
29 |
-
|
30 |
-
def extract_data(file, min_frequency=1):
|
31 |
try:
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
content = f.read()
|
37 |
-
|
38 |
soup = BeautifulSoup(content, 'html.parser')
|
39 |
desc_containers = soup.find_all('div', class_=lambda x: x and 'DivDesContainer' in x)
|
40 |
|
|
|
|
|
|
|
|
|
41 |
data = []
|
42 |
hashtags_counter = Counter()
|
43 |
|
44 |
for container in desc_containers[:500]:
|
45 |
title = container.get('aria-label', 'بدون عنوان')
|
46 |
-
|
47 |
-
|
48 |
-
|
|
|
49 |
hashtags_counter.update(hashtags)
|
|
|
50 |
|
51 |
-
|
52 |
-
|
53 |
df_titles = pd.DataFrame(data)
|
|
|
|
|
54 |
df_hashtags = pd.DataFrame(
|
55 |
-
[(tag, count
|
56 |
-
columns=["الهاشتاغ", "عدد التكرار"
|
57 |
).sort_values(by="عدد التكرار", ascending=False)
|
58 |
|
59 |
return df_titles, df_hashtags
|
60 |
|
61 |
except Exception as e:
|
62 |
-
return f"حدث
|
63 |
-
|
64 |
-
def create_downloadable_files(df_titles, df_hashtags, format_choice):
|
65 |
-
buffer = BytesIO()
|
66 |
-
|
67 |
-
if format_choice == "Excel":
|
68 |
-
with pd.ExcelWriter(buffer, engine='xlsxwriter') as writer:
|
69 |
-
df_titles.to_excel(writer, index=False, sheet_name='Titles')
|
70 |
-
df_hashtags.to_excel(writer, index=False, sheet_name='Hashtags')
|
71 |
-
elif format_choice == "Word":
|
72 |
-
doc = Document()
|
73 |
-
doc.add_heading("العناوين والهاشتاغات", level=1)
|
74 |
-
for _, row in df_titles.iterrows():
|
75 |
-
doc.add_paragraph(f"العنوان: {row['العنوان']}\nالكلمات الرئيسية: {row['الكلمات الرئيسية']}\nالهاشتاغات: {row['الهاشتاغات']}\n")
|
76 |
-
doc.add_heading("الهاشتاغات وتكرارها", level=1)
|
77 |
-
for _, row in df_hashtags.iterrows():
|
78 |
-
doc.add_paragraph(f"{row['الهاشتاغ']}: {row['عدد التكرار']} ({row['المجال']})")
|
79 |
-
doc.save(buffer)
|
80 |
-
elif format_choice == "TXT":
|
81 |
-
content = "العناوين والهاشتاغات:\n"
|
82 |
-
for _, row in df_titles.iterrows():
|
83 |
-
content += f"العنوان: {row['العنوان']}\nالكلمات الرئيسية: {row['الكلمات الرئيسية']}\nالهاشتاغات: {row['الهاشتاغات']}\n\n"
|
84 |
-
content += "الهاشتاغات وتكرارها:\n"
|
85 |
-
for _, row in df_hashtags.iterrows():
|
86 |
-
content += f"{row['الهاشتاغ']}: {row['عدد التكرار']} ({row['المجال']})\n"
|
87 |
-
buffer.write(content.encode('utf-8'))
|
88 |
-
buffer.seek(0)
|
89 |
-
return buffer, f"data.{format_choice.lower()}"
|
90 |
|
|
|
91 |
def gradio_interface():
|
92 |
-
with gr.Blocks(
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
|
101 |
-
with gr.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
102 |
with gr.TabItem("العناوين"):
|
103 |
titles_output = gr.HTML(label="العناوين")
|
|
|
104 |
with gr.TabItem("الهاشتاغات"):
|
105 |
hashtags_output = gr.HTML(label="الهاشتاغات")
|
|
|
|
|
|
|
|
|
|
|
106 |
|
|
|
107 |
analyze_btn.click(
|
108 |
-
fn=
|
109 |
-
inputs=[file_input,
|
110 |
-
outputs=[titles_output, hashtags_output]
|
111 |
)
|
112 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
return demo
|
114 |
|
115 |
# تشغيل التطبيق
|
116 |
-
|
117 |
-
|
|
|
1 |
+
import gradio as gr
|
2 |
import pandas as pd
|
3 |
+
from bs4 import BeautifulSoup
|
4 |
from collections import Counter
|
5 |
from io import BytesIO
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
|
7 |
+
# دالة لتحليل البيانات واستخراج العناوين والهاشتاغات
|
8 |
+
def analyze_tiktok_data(file, min_frequency):
|
|
|
|
|
|
|
|
|
|
|
9 |
try:
|
10 |
+
# قراءة محتوى الملف
|
11 |
+
content = file.read().decode('utf-8') if isinstance(file.read(), bytes) else file.read()
|
12 |
+
|
13 |
+
# تحليل HTML باستخدام BeautifulSoup
|
|
|
|
|
14 |
soup = BeautifulSoup(content, 'html.parser')
|
15 |
desc_containers = soup.find_all('div', class_=lambda x: x and 'DivDesContainer' in x)
|
16 |
|
17 |
+
if not desc_containers:
|
18 |
+
return "لم يتم العثور على بيانات متطابقة", None
|
19 |
+
|
20 |
+
# استخراج البيانات
|
21 |
data = []
|
22 |
hashtags_counter = Counter()
|
23 |
|
24 |
for container in desc_containers[:500]:
|
25 |
title = container.get('aria-label', 'بدون عنوان')
|
26 |
+
hashtags = [
|
27 |
+
tag.get_text(strip=True) for tag in container.find_all(['a', 'span'])
|
28 |
+
if tag.get_text(strip=True).startswith('#')
|
29 |
+
]
|
30 |
hashtags_counter.update(hashtags)
|
31 |
+
data.append({"العنوان": title, "الهاشتاغات": ", ".join(hashtags)})
|
32 |
|
33 |
+
# إنشاء DataFrame للعناوين والهاشتاغات
|
|
|
34 |
df_titles = pd.DataFrame(data)
|
35 |
+
|
36 |
+
# تصفية الهاشتاغات حسب التكرار
|
37 |
df_hashtags = pd.DataFrame(
|
38 |
+
[(tag, count) for tag, count in hashtags_counter.items() if count >= min_frequency],
|
39 |
+
columns=["الهاشتاغ", "عدد التكرار"]
|
40 |
).sort_values(by="عدد التكرار", ascending=False)
|
41 |
|
42 |
return df_titles, df_hashtags
|
43 |
|
44 |
except Exception as e:
|
45 |
+
return f"حدث خطأ أثناء التحليل: {str(e)}", None
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
46 |
|
47 |
+
# إنشاء واجهة Gradio
|
48 |
def gradio_interface():
|
49 |
+
with gr.Blocks(css="""
|
50 |
+
.container {
|
51 |
+
max-width: 800px;
|
52 |
+
margin: auto;
|
53 |
+
padding: 20px;
|
54 |
+
}
|
55 |
+
.btn-primary {
|
56 |
+
background-color: #4CAF50;
|
57 |
+
color: white;
|
58 |
+
}
|
59 |
+
.table {
|
60 |
+
width: 100%;
|
61 |
+
border-collapse: collapse;
|
62 |
+
margin-bottom: 20px;
|
63 |
+
}
|
64 |
+
.table th, .table td {
|
65 |
+
border: 1px solid #ddd;
|
66 |
+
padding: 8px;
|
67 |
+
}
|
68 |
+
.table th {
|
69 |
+
background-color: #f2f2f2;
|
70 |
+
text-align: left;
|
71 |
+
}
|
72 |
+
""") as demo:
|
73 |
+
gr.Markdown("## مستخرج الهاشتاغات والعناوين من TikTok 🏷️", elem_classes=["container"])
|
74 |
|
75 |
+
with gr.Row(elem_classes=["container"]):
|
76 |
+
file_input = gr.File(label="ارفع ملف HTML")
|
77 |
+
min_freq_slider = gr.Slider(
|
78 |
+
minimum=1, maximum=50, value=1, label="الحد الأدنى لتكرار الهاشتاغ"
|
79 |
+
)
|
80 |
+
|
81 |
+
analyze_btn = gr.Button("تحليل البيانات", elem_classes=["btn-primary"])
|
82 |
+
|
83 |
+
with gr.Tabs(elem_classes=["container"]):
|
84 |
with gr.TabItem("العناوين"):
|
85 |
titles_output = gr.HTML(label="العناوين")
|
86 |
+
|
87 |
with gr.TabItem("الهاشتاغات"):
|
88 |
hashtags_output = gr.HTML(label="الهاشتاغات")
|
89 |
+
with gr.Row():
|
90 |
+
copy_btn = gr.Button("نسخ الهاشتاغات", elem_classes=["btn-primary"])
|
91 |
+
hashtags_textbox = gr.Textbox(
|
92 |
+
label="نسخ الهاشتاغات هنا", visible=False, interactive=False
|
93 |
+
)
|
94 |
|
95 |
+
# عند الضغط على زر التحليل
|
96 |
analyze_btn.click(
|
97 |
+
fn=analyze_tiktok_data,
|
98 |
+
inputs=[file_input, min_freq_slider],
|
99 |
+
outputs=[titles_output, hashtags_output],
|
100 |
)
|
101 |
+
|
102 |
+
# نسخ الهاشتاغات إلى مربع النص
|
103 |
+
copy_btn.click(
|
104 |
+
fn=lambda df_titles, df_hashtags: "\n".join(df_hashtags["الهاشتاغ"].tolist()) if df_hashtags is not None else "",
|
105 |
+
inputs=[file_input, min_freq_slider],
|
106 |
+
outputs=hashtags_textbox,
|
107 |
+
)
|
108 |
+
hashtags_textbox.change(visible=True)
|
109 |
+
|
110 |
return demo
|
111 |
|
112 |
# تشغيل التطبيق
|
113 |
+
demo = gradio_interface()
|
114 |
+
demo.launch()
|