""" 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' 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 'متوسط - تحسين تدريجي'