File size: 13,371 Bytes
a74b879
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
"""
Action Plan Generator
Automatically generates actionable SEO and GEO recommendations
"""

from typing import Dict, List
import json

def generate_action_plan_from_audit(audit: Dict) -> Dict:
    """
    Generate comprehensive action plan from audit results
    Returns prioritized, actionable tasks
    """
    pages = audit.get('pages', [])
    geo_score = audit.get('geo_score', 0)
    ai_visibility = audit.get('ai_visibility', {})
    
    actions = []
    
    # 1. Critical Issues (High Priority)
    actions.extend(_generate_critical_actions(audit, pages))
    
    # 2. SEO Issues (High Priority)
    actions.extend(_generate_seo_actions(pages))
    
    # 3. Content Issues (Medium Priority)
    actions.extend(_generate_content_actions(pages))
    
    # 4. AI Visibility Issues (Medium Priority)
    actions.extend(_generate_ai_visibility_actions(ai_visibility, geo_score))
    
    # 5. Technical Issues (Low Priority)
    actions.extend(_generate_technical_actions(pages))
    
    # Sort by priority
    priority_order = {'critical': 0, 'high': 1, 'medium': 2, 'low': 3}
    actions.sort(key=lambda x: priority_order.get(x['priority'], 4))
    
    # Calculate completion stats
    total_actions = len(actions)
    critical_count = len([a for a in actions if a['priority'] == 'critical'])
    high_count = len([a for a in actions if a['priority'] == 'high'])
    
    return {
        'ok': True,
        'actions': actions,
        'summary': {
            'total': total_actions,
            'critical': critical_count,
            'high': high_count,
            'medium': len([a for a in actions if a['priority'] == 'medium']),
            'low': len([a for a in actions if a['priority'] == 'low'])
        },
        'estimated_time': _estimate_total_time(actions),
        'estimated_impact': _estimate_total_impact(actions)
    }


def _generate_critical_actions(audit: Dict, pages: List[Dict]) -> List[Dict]:
    """Generate critical priority actions"""
    actions = []
    
    # Check for pages with 0 words
    empty_pages = [p for p in pages if p.get('word_count', 0) < 100]
    if empty_pages:
        actions.append({
            'id': 'critical_empty_content',
            'type': 'content',
            'priority': 'critical',
            'title': f'محتوى فارغ في {len(empty_pages)} صفحة',
            'description': 'صفحات بدون محتوى كافٍ لن تظهر في نتائج البحث أو الذكاء الاصطناعي',
            'task': f'أضف محتوى تفصيلي (600+ كلمة) لـ {len(empty_pages)} صفحة',
            'impact': 'عالي جداً',
            'effort': 'متوسط',
            'timeline': f'{len(empty_pages) * 2} ساعة',
            'pages_affected': [p.get('url') for p in empty_pages[:5]]
        })
    
    # Check for missing Schema
    pages_without_schema = [p for p in pages if not _has_schema(p)]
    if len(pages_without_schema) == len(pages):
        actions.append({
            'id': 'critical_no_schema',
            'type': 'technical',
            'priority': 'critical',
            'title': 'لا يوجد Schema Markup',
            'description': 'Schema Markup ضروري للظهور في نتائج الذكاء الاصطناعي',
            'task': 'أضف Organization و FAQPage Schema لجميع الصفحات',
            'impact': 'عالي جداً',
            'effort': 'منخفض',
            'timeline': '2 ساعة',
            'code_example': 'استخدم schema_generator.py'
        })
    
    return actions


def _generate_seo_actions(pages: List[Dict]) -> List[Dict]:
    """Generate SEO-related actions"""
    actions = []
    
    # Missing meta descriptions
    pages_without_meta = [p for p in pages if not _has_meta_description(p)]
    if pages_without_meta:
        actions.append({
            'id': 'seo_meta_descriptions',
            'type': 'seo',
            'priority': 'high',
            'title': f'Meta Description مفقود في {len(pages_without_meta)} صفحة',
            'description': 'Meta descriptions تحسن نسبة النقر في نتائج البحث',
            'task': f'أضف meta description مُحسّن لـ {len(pages_without_meta)} صفحة',
            'impact': 'عالي',
            'effort': 'منخفض',
            'timeline': f'{len(pages_without_meta) * 15} دقيقة',
            'pages_affected': [p.get('url') for p in pages_without_meta[:5]],
            'tool': 'استخدم meta_generator.py'
        })
    
    # Missing H1 tags
    pages_without_h1 = [p for p in pages if not _has_h1(p)]
    if pages_without_h1:
        actions.append({
            'id': 'seo_h1_tags',
            'type': 'seo',
            'priority': 'high',
            'title': f'H1 مفقود في {len(pages_without_h1)} صفحة',
            'description': 'H1 tag ضروري لمحركات البحث لفهم موضوع الصفحة',
            'task': f'أضف H1 واضح ومُحسّن لـ {len(pages_without_h1)} صفحة',
            'impact': 'عالي',
            'effort': 'منخفض',
            'timeline': f'{len(pages_without_h1) * 10} دقيقة',
            'pages_affected': [p.get('url') for p in pages_without_h1[:5]]
        })
    
    # Duplicate titles
    titles = [p.get('title', '') for p in pages]
    duplicate_titles = [t for t in titles if titles.count(t) > 1]
    if duplicate_titles:
        actions.append({
            'id': 'seo_duplicate_titles',
            'type': 'seo',
            'priority': 'medium',
            'title': f'{len(set(duplicate_titles))} عنوان مكرر',
            'description': 'العناوين المكررة تضعف أداء SEO',
            'task': 'اجعل كل عنوان صفحة فريد ووصفي',
            'impact': 'متوسط',
            'effort': 'منخفض',
            'timeline': '1 ساعة'
        })
    
    return actions


def _generate_content_actions(pages: List[Dict]) -> List[Dict]:
    """Generate content-related actions"""
    actions = []
    
    # Low content density
    thin_pages = [p for p in pages if 100 < p.get('word_count', 0) < 300]
    if thin_pages:
        actions.append({
            'id': 'content_thin_pages',
            'type': 'content',
            'priority': 'medium',
            'title': f'محتوى ضعيف في {len(thin_pages)} صفحة',
            'description': 'الصفحات ذات المحتوى القليل تحصل على ترتيب أقل',
            'task': f'وسّع المحتوى إلى 600+ كلمة في {len(thin_pages)} صفحة',
            'impact': 'متوسط',
            'effort': 'متوسط',
            'timeline': f'{len(thin_pages) * 1.5} ساعة',
            'pages_affected': [p.get('url') for p in thin_pages[:5]]
        })
    
    # No entities (for AI visibility)
    pages_without_entities = [p for p in pages if len(p.get('entities', [])) < 3]
    if len(pages_without_entities) > len(pages) * 0.5:
        actions.append({
            'id': 'content_entities',
            'type': 'content',
            'priority': 'medium',
            'title': 'محتوى غير منظم - لا كيانات معرفية',
            'description': 'الذكاء الاصطناعي يحتاج كيانات واضحة (أسماء، أماكن، منتجات)',
            'task': 'أضف أسماء محددة، أرقام، وأماكن في المحتوى',
            'impact': 'عالي',
            'effort': 'متوسط',
            'timeline': '3 ساعات',
            'example': 'بدلاً من "نقدم خدمات ممتازة" → "نقدم خدمات SEO في الرياض منذ 2020"'
        })
    
    return actions


def _generate_ai_visibility_actions(ai_visibility: Dict, geo_score: int) -> List[Dict]:
    """Generate AI visibility improvement actions"""
    actions = []
    
    if geo_score < 50:
        actions.append({
            'id': 'ai_low_geo_score',
            'type': 'ai_visibility',
            'priority': 'high',
            'title': f'درجة GEO منخفضة ({geo_score}/100)',
            'description': 'موقعك غير مرئي في محركات الذكاء الاصطناعي',
            'task': 'نفّذ جميع التوصيات لرفع درجة GEO',
            'impact': 'عالي جداً',
            'effort': 'عالي',
            'timeline': '2-4 أسابيع',
            'steps': [
                'أضف محتوى تفصيلي 600+ كلمة',
                'أضف Schema Markup',
                'أضف FAQ Schema',
                'حسّن الكيانات المعرفية',
                'أضف روابط خارجية موثوقة'
            ]
        })
    
    mentions = ai_visibility.get('mentions', 0)
    if mentions == 0:
        actions.append({
            'id': 'ai_no_mentions',
            'type': 'ai_visibility',
            'priority': 'high',
            'title': 'لا يوجد ذكر في الذكاء الاصطناعي',
            'description': 'علامتك التجارية غير معروفة لمحركات الذكاء الاصطناعي',
            'task': 'بناء حضور رقمي قوي',
            'impact': 'عالي',
            'effort': 'عالي',
            'timeline': '4-8 أسابيع',
            'steps': [
                'انشر محتوى عالي الجودة بانتظام',
                'احصل على روابط من مواقع موثوقة',
                'شارك في المنتديات والمجتمعات',
                'أنشئ ملفات تعريف في الدلائل الرئيسية'
            ]
        })
    
    return actions


def _generate_technical_actions(pages: List[Dict]) -> List[Dict]:
    """Generate technical SEO actions"""
    actions = []
    
    # Check for mobile-friendliness
    actions.append({
        'id': 'technical_mobile',
        'type': 'technical',
        'priority': 'medium',
        'title': 'فحص التوافق مع الموبايل',
        'description': 'تأكد من أن الموقع متجاوب على جميع الأجهزة',
        'task': 'اختبر الموقع على أجهزة مختلفة وأصلح المشاكل',
        'impact': 'عالي',
        'effort': 'متوسط',
        'timeline': '1-2 أيام',
        'tool': 'استخدم mobile_checker.py'
    })
    
    # Check page speed
    actions.append({
        'id': 'technical_speed',
        'type': 'technical',
        'priority': 'low',
        'title': 'تحسين سرعة الموقع',
        'description': 'المواقع السريعة تحصل على ترتيب أفضل',
        'task': 'ضغط الصور، تفعيل التخزين المؤقت، تصغير CSS/JS',
        'impact': 'متوسط',
        'effort': 'متوسط',
        'timeline': '2-3 أيام'
    })
    
    return actions


def _has_schema(page: Dict) -> bool:
    """Check if page has Schema markup"""
    html = page.get('html', '')
    return 'application/ld+json' in html or '@type' in html


def _has_meta_description(page: Dict) -> bool:
    """Check if page has meta description"""
    html = page.get('html', '')
    import re
    return bool(re.search(r'<meta\s+name=["\']description["\']', html, re.IGNORECASE))


def _has_h1(page: Dict) -> bool:
    """Check if page has H1 tag"""
    headings = page.get('headings', [])
    for h in headings:
        if isinstance(h, dict) and h.get('level') == 1:
            return True
        elif isinstance(h, str) and h.startswith('h1'):
            return True
    return False


def _estimate_total_time(actions: List[Dict]) -> str:
    """Estimate total time to complete all actions"""
    total_hours = 0
    for action in actions:
        timeline = action.get('timeline', '')
        if 'ساعة' in timeline or 'hour' in timeline:
            import re
            match = re.search(r'(\d+(?:\.\d+)?)', timeline)
            if match:
                total_hours += float(match.group(1))
        elif 'دقيقة' in timeline or 'minute' in timeline:
            import re
            match = re.search(r'(\d+)', timeline)
            if match:
                total_hours += float(match.group(1)) / 60
        elif 'يوم' in timeline or 'day' in timeline:
            import re
            match = re.search(r'(\d+)', timeline)
            if match:
                total_hours += float(match.group(1)) * 8
        elif 'أسبوع' in timeline or 'week' in timeline:
            import re
            match = re.search(r'(\d+)', timeline)
            if match:
                total_hours += float(match.group(1)) * 40
    
    if total_hours < 8:
        return f'{int(total_hours)} ساعة'
    elif total_hours < 40:
        return f'{int(total_hours / 8)} يوم'
    else:
        return f'{int(total_hours / 40)} أسبوع'


def _estimate_total_impact(actions: List[Dict]) -> str:
    """Estimate total impact of completing all actions"""
    high_impact = len([a for a in actions if a.get('impact') in ['عالي جداً', 'عالي', 'high']])
    
    if high_impact > 5:
        return 'عالي جداً - تحسين كبير متوقع'
    elif high_impact > 2:
        return 'عالي - تحسين ملحوظ متوقع'
    else:
        return 'متوسط - تحسين تدريجي'