"""
Meta Description Generator
AI-powered meta description generation for SEO
"""
import os
import re
from typing import Dict, List
def generate_meta_description(page: Dict, api_keys: Dict = None) -> str:
"""
Generate SEO-optimized meta description for a page
Uses AI if available, falls back to smart extraction
"""
title = page.get('title', '')
text = page.get('text', '')
headings = page.get('headings', [])
url = page.get('url', '')
# Try AI generation first
ai_description = _generate_with_ai(title, text, headings, api_keys)
if ai_description:
return ai_description
# Fallback to smart extraction
return _generate_smart_description(title, text, headings)
def _generate_with_ai(title: str, text: str, headings: List, api_keys: Dict = None) -> str:
"""Generate meta description using AI (Groq or OpenAI)"""
try:
# Try Groq first (faster and free)
groq_key = (api_keys or {}).get('groq') or os.getenv('GROQ_API_KEY')
if groq_key:
return _generate_with_groq(title, text, headings, groq_key)
# Fallback to OpenAI
openai_key = (api_keys or {}).get('openai') or os.getenv('OPENAI_API_KEY')
if openai_key:
return _generate_with_openai(title, text, headings, openai_key)
return None
except Exception as e:
print(f"AI meta generation failed: {e}")
return None
def _generate_with_groq(title: str, text: str, headings: List, api_key: str) -> str:
"""Generate using Groq API"""
try:
import requests
# Extract key points from text
text_sample = text[:1000] if text else ''
headings_text = ' '.join([h.get('text', '') if isinstance(h, dict) else str(h) for h in headings[:5]])
prompt = f"""اكتب وصف meta description مثالي لصفحة ويب بالمواصفات التالية:
- العنوان: {title}
- المحتوى: {text_sample}
- العناوين: {headings_text}
المتطلبات:
- الطول: 150-160 حرف بالضبط
- يجب أن يكون جذاب ومقنع
- يحتوي على كلمات مفتاحية
- يشجع على النقر
- بدون علامات تنصيص
اكتب الوصف فقط بدون أي نص إضافي:"""
response = requests.post(
'https://api.groq.com/openai/v1/chat/completions',
headers={
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
},
json={
'model': 'llama-3.3-70b-versatile',
'messages': [{'role': 'user', 'content': prompt}],
'temperature': 0.7,
'max_tokens': 100
},
timeout=15
)
if response.status_code == 200:
data = response.json()
description = data['choices'][0]['message']['content'].strip()
# Clean up
description = description.replace('"', '').replace("'", '').strip()
# Ensure proper length
if len(description) > 160:
description = description[:157] + '...'
return description
return None
except Exception as e:
print(f"Groq meta generation error: {e}")
return None
def _generate_with_openai(title: str, text: str, headings: List, api_key: str) -> str:
"""Generate using OpenAI API"""
try:
import requests
text_sample = text[:1000] if text else ''
headings_text = ' '.join([h.get('text', '') if isinstance(h, dict) else str(h) for h in headings[:5]])
prompt = f"""Write a perfect meta description for a webpage with these details:
- Title: {title}
- Content: {text_sample}
- Headings: {headings_text}
Requirements:
- Exactly 150-160 characters
- Compelling and click-worthy
- Contains keywords
- No quotation marks
Write only the description:"""
response = requests.post(
'https://api.openai.com/v1/chat/completions',
headers={
'Authorization': f'Bearer {api_key}',
'Content-Type': 'application/json'
},
json={
'model': 'gpt-3.5-turbo',
'messages': [{'role': 'user', 'content': prompt}],
'temperature': 0.7,
'max_tokens': 100
},
timeout=15
)
if response.status_code == 200:
data = response.json()
description = data['choices'][0]['message']['content'].strip()
description = description.replace('"', '').replace("'", '').strip()
if len(description) > 160:
description = description[:157] + '...'
return description
return None
except Exception as e:
print(f"OpenAI meta generation error: {e}")
return None
def _generate_smart_description(title: str, text: str, headings: List) -> str:
"""Generate meta description using smart extraction (no AI)"""
# Clean text
text = re.sub(r'\s+', ' ', text).strip()
# Try to find first meaningful paragraph
sentences = re.split(r'[.!?]+', text)
description = ''
for sentence in sentences:
sentence = sentence.strip()
if len(sentence) > 50 and len(sentence) < 200:
description = sentence
break
# If no good sentence, use title + first heading
if not description and headings:
first_heading = headings[0]
heading_text = first_heading.get('text', '') if isinstance(first_heading, dict) else str(first_heading)
description = f"{title} - {heading_text}"
# If still nothing, use title + generic text
if not description:
description = f"{title} - اكتشف خدماتنا ومنتجاتنا المتميزة"
# Ensure proper length
if len(description) > 160:
description = description[:157] + '...'
elif len(description) < 120:
description += ' - تواصل معنا الآن للمزيد من المعلومات'
return description
def generate_meta_descriptions_for_audit(audit: Dict, api_keys: Dict = None) -> List[Dict]:
"""Generate meta descriptions for all pages in audit"""
pages = audit.get('pages', [])
results = []
for page in pages:
url = page.get('url', '')
title = page.get('title', '')
# Check if page already has meta description
html = page.get('html', '')
existing_meta = re.search(r' 160:
issues.append('طويل جداً (أكثر من 160 حرف)')
if not any(keyword in existing_description.lower() for keyword in title.lower().split()[:3]):
issues.append('لا يحتوي على كلمات مفتاحية من العنوان')
results.append({
'url': url,
'title': title,
'has_meta': has_meta,
'existing': existing_description,
'suggested': new_description,
'issues': issues,
'status': 'جيد ✓' if has_meta and not issues else 'يحتاج تحسين ⚠️' if has_meta else 'مفقود ❌'
})
return results
def get_meta_description_recommendations(audit: Dict) -> Dict:
"""Get summary and recommendations for meta descriptions"""
pages = audit.get('pages', [])
total_pages = len(pages)
pages_with_meta = 0
pages_with_good_meta = 0
pages_missing_meta = 0
for page in pages:
html = page.get('html', '')
meta_match = re.search(r' 0 else 0
recommendations = []
if pages_missing_meta > 0:
recommendations.append(f'أضف meta description لـ {pages_missing_meta} صفحة')
if pages_with_meta - pages_with_good_meta > 0:
recommendations.append(f'حسّن meta description لـ {pages_with_meta - pages_with_good_meta} صفحة')
return {
'score': score,
'total_pages': total_pages,
'pages_with_meta': pages_with_meta,
'pages_with_good_meta': pages_with_good_meta,
'pages_missing_meta': pages_missing_meta,
'status': 'ممتاز ✅' if score >= 90 else 'جيد ✓' if score >= 70 else 'يحتاج تحسين ⚠️',
'recommendations': recommendations
}