mroccuper commited on
Commit
2ccda21
Β·
verified Β·
1 Parent(s): 065776f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +586 -338
app.py CHANGED
@@ -4,373 +4,621 @@ import textstat
4
  import re
5
  import requests
6
  from urllib.parse import urlparse
7
-
8
- # --- Sanitize for f-string ---
9
- def sanitize_for_fstring(text):
10
- return text.replace('{', '{{').replace('}', '}}')
11
-
12
- # --- Semantic SEO Enhancement ---
13
- def generate_semantic_keywords(keyword):
14
- """Generate semantic variations of the primary keyword"""
15
- words = keyword.lower().split()
16
- variations = []
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
- # Add common semantic variations
19
- semantic_map = {
20
- 'benefits': ['advantages', 'pros', 'positive effects', 'value', 'perks'],
21
- 'tips': ['advice', 'strategies', 'recommendations', 'guidelines', 'hacks'],
22
- 'guide': ['tutorial', 'handbook', 'instructions', 'walkthrough', 'manual'],
23
- 'best': ['top', 'excellent', 'outstanding', 'premier', 'finest'],
24
- 'how to': ['ways to', 'methods to', 'steps to', 'process of'],
25
- 'review': ['analysis', 'evaluation', 'assessment', 'examination'],
26
- 'comparison': ['versus', 'difference', 'contrast', 'alternative']
27
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
- for word in words:
30
- if word in semantic_map:
31
- variations.extend(semantic_map[word])
32
 
33
- # Add plurals and singulars
34
- for word in words:
35
- if word.endswith('s') and len(word) > 3:
36
- variations.append(word[:-1]) # Remove 's' for singular
37
- elif not word.endswith('s'):
38
- variations.append(word + 's') # Add 's' for plural
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
 
40
- return list(set(variations))
 
 
 
 
 
 
 
41
 
42
- # --- Enhanced Readability Analysis ---
43
- def analyze_text_advanced(text, keyword):
44
- """Enhanced readability analysis with interpretation"""
45
- flesch_score = textstat.flesch_reading_ease(text)
46
- gunning_fog = textstat.gunning_fog(text)
47
- word_count = len(text.split())
48
- sentence_count = textstat.sentence_count(text)
49
- avg_sentence_length = word_count / sentence_count if sentence_count > 0 else 0
50
 
51
- # Keyword analysis
52
- keyword_count = text.lower().count(keyword.lower())
53
- density = round((keyword_count / word_count) * 100, 2) if word_count > 0 else 0
54
 
55
- # Readability interpretation
56
- if flesch_score >= 90:
57
- readability_level = "Very Easy (5th grade)"
58
- elif flesch_score >= 80:
59
- readability_level = "Easy (6th grade)"
60
- elif flesch_score >= 70:
61
- readability_level = "Fairly Easy (7th grade)"
62
- elif flesch_score >= 60:
63
- readability_level = "Standard (8th-9th grade)"
64
- elif flesch_score >= 50:
65
- readability_level = "Fairly Difficult (10th-12th grade)"
66
- elif flesch_score >= 30:
67
- readability_level = "Difficult (College level)"
 
 
 
 
 
 
68
  else:
69
- readability_level = "Very Difficult (Graduate level)"
70
 
71
- return {
72
- 'flesch_score': flesch_score,
73
- 'gunning_fog': gunning_fog,
74
- 'readability_level': readability_level,
75
- 'word_count': word_count,
76
- 'sentence_count': sentence_count,
77
- 'avg_sentence_length': round(avg_sentence_length, 1),
78
- 'keyword_count': keyword_count,
79
- 'keyword_density': density
80
- }
81
-
82
- # --- Image Alt Text Generator ---
83
- def generate_image_alt_texts(keyword, num_sections=5):
84
- """Generate alt text suggestions for images based on keyword"""
85
- alt_texts = [
86
- f"Infographic showing {keyword} overview",
87
- f"Step-by-step guide for {keyword}",
88
- f"Visual representation of {keyword} benefits",
89
- f"Comparison chart related to {keyword}",
90
- f"Real-world example of {keyword} in action"
91
- ]
92
- return alt_texts[:num_sections]
93
-
94
- # --- CTA Personalization ---
95
- def generate_personalized_cta(emotion, tone, keyword):
96
- """Generate personalized CTAs based on emotion and tone"""
97
- cta_templates = {
98
- 'Trust': {
99
- 'Friendly': f"Ready to explore {keyword}? Share your thoughts below!",
100
- 'Professional': f"Implement these {keyword} strategies and let us know your results.",
101
- 'Motivational': f"Take action on {keyword} today - your success story starts now!"
102
- },
103
- 'Excitement': {
104
- 'Friendly': f"Excited about {keyword}? Tell us what you're planning to try first!",
105
- 'Professional': f"Ready to leverage {keyword}? Connect with our team for expert guidance.",
106
- 'Motivational': f"Don't wait - start your {keyword} journey today!"
107
- },
108
- 'Curiosity': {
109
- 'Friendly': f"What's your experience with {keyword}? We'd love to hear from you!",
110
- 'Professional': f"Have questions about {keyword}? Our experts are here to help.",
111
- 'Motivational': f"Discover more about {keyword} - your next breakthrough awaits!"
112
- },
113
- 'Confidence': {
114
- 'Friendly': f"Feel confident about {keyword} now? Share your success story!",
115
- 'Professional': f"Ready to implement {keyword} with confidence? Get started today.",
116
- 'Motivational': f"You have everything you need for {keyword} success - take the first step!"
117
- },
118
- 'Inspiration': {
119
- 'Friendly': f"Feeling inspired about {keyword}? Let's continue the conversation!",
120
- 'Professional': f"Transform your approach to {keyword} with our proven methods.",
121
- 'Motivational': f"Your {keyword} transformation starts now - make it happen!"
122
- }
123
- }
124
 
125
- return cta_templates.get(emotion, {}).get(tone, f"What are your thoughts on {keyword}? Share below!")
126
-
127
- # --- Human Tone Enforcement ---
128
- def create_human_tone_prompt(keyword, tone, emotion, pov):
129
- """Create prompts that enforce human-like writing"""
130
- anti_ai_phrases = [
131
- "Avoid starting with 'In conclusion', 'In summary', or 'To summarize'",
132
- "Don't use phrases like 'delve into', 'dive deep', 'it's worth noting'",
133
- "Skip generic openings like 'In today's digital world' or 'In this comprehensive guide'",
134
- "Use contractions naturally (don't, won't, can't, you'll)",
135
- "Write with personal experience and specific examples",
136
- "Vary sentence length - mix short punchy sentences with longer explanatory ones"
137
- ]
138
 
139
- human_elements = [
140
- "Include personal anecdotes or relatable scenarios",
141
- "Use conversational transitions like 'Here's the thing' or 'But wait, there's more'",
142
- "Add rhetorical questions to engage readers",
143
- "Include specific numbers, dates, or statistics when relevant",
144
- "Use storytelling elements to make points memorable"
145
- ]
146
 
147
- return f"""
148
- Write in a genuinely human {tone.lower()} tone with {emotion.lower()} emotion using {pov}.
 
 
149
 
150
- AVOID these AI-like patterns:
151
- {chr(10).join('- ' + phrase for phrase in anti_ai_phrases)}
 
152
 
153
- INCLUDE these human elements:
154
- {chr(10).join('- ' + element for element in human_elements)}
 
155
 
156
- Write like you're having a conversation with a friend who asked about {keyword}.
157
- """
158
-
159
- # --- Error Handling ---
160
- def safe_api_call(model, prompt, max_retries=3):
161
- """Safely call the API with error handling"""
162
- for attempt in range(max_retries):
163
- try:
164
- response = model.generate_content(prompt)
165
- if response.text:
166
- return response.text
167
- else:
168
- raise Exception("Empty response from API")
169
- except Exception as e:
170
- if attempt == max_retries - 1:
171
- return f"Error generating content: {str(e)}. Please check your API key and try again."
172
- continue
173
- return "Failed to generate content after multiple attempts."
174
-
175
- # --- Main Article Generation ---
176
- def generate_article(api_key, keyword, plan, pov, tone, length, emotion, show_titles, show_readability, target_keywords, links_input, cta_text, include_alt_texts, include_faqs):
177
 
178
- if not api_key or not keyword or not plan:
179
- return "Please provide API key, keyword, and SEO plan to generate content."
 
 
 
 
 
 
 
 
 
 
 
 
 
180
 
181
  try:
182
- genai.configure(api_key=api_key)
183
- model = genai.GenerativeModel('gemini-1.5-pro')
 
184
  except Exception as e:
185
- return f"Error configuring API: {str(e)}"
186
-
187
- # Generate semantic keywords
188
- semantic_keywords = generate_semantic_keywords(keyword)
189
- all_keywords = [keyword] + (target_keywords.split(',') if target_keywords else []) + semantic_keywords[:5]
190
 
191
- # Auto-detect internal link suggestions
192
- internal_links = ""
193
- if links_input.strip():
194
- for line in links_input.strip().splitlines():
195
- if ":" in line:
196
- anchor, url = line.split(":", 1)
197
- internal_links += f'<p><strong>Related:</strong> <a href="{url.strip()}">{anchor.strip()}</a></p>\n'
198
-
199
- # Generate personalized CTA if not provided
200
- if not cta_text:
201
- cta_text = generate_personalized_cta(emotion, tone, keyword)
202
-
203
- # Human tone enforcement
204
- human_tone_guide = create_human_tone_prompt(keyword, tone, emotion, pov)
205
 
206
- # Compose the enhanced prompt
207
- prompt = f"""
208
- {human_tone_guide}
209
-
210
- Generate a comprehensive, WordPress-optimized blog post with proper SEO structure.
211
-
212
- ARTICLE REQUIREMENTS:
213
- - Primary keyword: "{keyword}"
214
- - Use these related keywords naturally: {', '.join(all_keywords)}
215
- - Tone: {tone}, POV: {pov}, Emotion: {emotion}
216
- - Include proper HTML structure for WordPress
217
- - Length target: {length}
218
-
219
- SEO STRUCTURE REQUIRED:
220
- 1. Compelling introduction (hook + keyword in first 100 words)
221
- 2. Multiple H2 sections covering different aspects
222
- 3. {"FAQ section with 3-5 questions" if include_faqs else ""}
223
- 4. Strong conclusion with the CTA
224
-
225
- SEO PLAN TO FOLLOW:
226
- {plan}
227
-
228
- INTERNAL LINKS TO INCLUDE:
229
- {links_input if links_input else "No internal links provided"}
230
-
231
- FINAL CTA TO USE:
232
- {cta_text}
233
-
234
- OUTPUT FORMAT:
235
- Use clean HTML suitable for WordPress. Include <h1>, <h2>, <h3>, <p>, <ul>, <li> tags as needed.
236
- Make it engaging, informative, and naturally optimized for "{keyword}".
237
- """
238
-
239
- # Generate main article
240
- article = safe_api_call(model, prompt)
241
- if "Error" in article:
242
- return article
243
-
244
- article = sanitize_for_fstring(article)
245
-
246
- # Generate meta description
247
- meta_desc_prompt = f"""
248
- Write a compelling meta description for a blog post about '{keyword}'.
249
- Requirements:
250
- - Under 160 characters
251
- - Include the primary keyword
252
- - Action-oriented and click-worthy
253
- - Match the {emotion.lower()} emotion
254
-
255
- Content summary: {article[:500]}...
256
- """
257
 
258
- meta_description = safe_api_call(model, meta_desc_prompt)
259
- meta_description = sanitize_for_fstring(meta_description.strip().replace("\n", " "))[:160]
260
-
261
- # SEO Title Variations
262
- title_prompt = f"""
263
- Create 3 SEO-optimized blog post titles for '{keyword}' that:
264
- - Include the primary keyword
265
- - Evoke {emotion.lower()} emotion
266
- - Are under 60 characters
267
- - Use power words and numbers where appropriate
268
- - Match {tone.lower()} tone
269
-
270
- Format as a numbered list.
271
- """
272
- titles = safe_api_call(model, title_prompt)
273
-
274
- # Advanced readability analysis
275
- analysis = analyze_text_advanced(article, keyword)
276
 
277
- # Generate image alt texts
278
- alt_texts = generate_image_alt_texts(keyword) if include_alt_texts else []
279
-
280
- # Build final output
281
- result_parts = [
282
- "<!-- βœ… WordPress Blog Article Output -->",
283
- f"<h1>{keyword.title()}</h1>",
284
- article,
285
- internal_links,
286
- "",
287
- "<!-- βœ… Rank Math Meta Description -->",
288
- f"<p><strong>Meta Description:</strong> {meta_description}</p>",
289
- ""
290
- ]
291
-
292
- if show_titles:
293
- result_parts.extend([
294
- "<!-- βœ… SEO Title Variations -->",
295
- f"<p><strong>Title Variations:</strong><br>{titles.replace(chr(10), '<br>')}</p>",
296
- ""
297
- ])
298
-
299
- if include_alt_texts and alt_texts:
300
- result_parts.extend([
301
- "<!-- βœ… Image Alt Text Suggestions -->",
302
- "<p><strong>Suggested Image Alt Texts:</strong></p>",
303
- "<ul>"
304
- ])
305
- for alt in alt_texts:
306
- result_parts.append(f"<li>{alt}</li>")
307
- result_parts.extend(["</ul>", ""])
308
-
309
- if show_readability:
310
- result_parts.extend([
311
- "<!-- βœ… Enhanced Readability & SEO Analysis -->",
312
- f"<div style='background:#f8f9fa;padding:15px;border-radius:5px;'>",
313
- f"<p><strong>πŸ“Š Readability Analysis:</strong></p>",
314
- f"<p>β€’ Flesch Reading Ease: {analysis['flesch_score']:.1f} ({analysis['readability_level']})</p>",
315
- f"<p>β€’ Gunning Fog Index: {analysis['gunning_fog']:.1f}</p>",
316
- f"<p>β€’ Average Sentence Length: {analysis['avg_sentence_length']} words</p>",
317
- f"<p><strong>🎯 SEO Metrics:</strong></p>",
318
- f"<p>β€’ Keyword '{keyword}' appears {analysis['keyword_count']} times</p>",
319
- f"<p>β€’ Keyword Density: {analysis['keyword_density']}% (optimal: 1-2%)</p>",
320
- f"<p>β€’ Total Words: {analysis['word_count']}</p>",
321
- f"<p>β€’ Total Sentences: {analysis['sentence_count']}</p>",
322
- f"</div>",
323
- ""
324
- ])
325
-
326
- result_parts.extend([
327
- "<!-- βœ… Semantic Keywords Used -->",
328
- f"<p><strong>πŸ”‘ Keywords Integrated:</strong> {', '.join(all_keywords[:10])}</p>"
329
- ])
330
-
331
- return '\n'.join(result_parts)
332
-
333
- # --- Gradio UI ---
334
- with gr.Blocks(css="#generate_button { background: #10b981 !important; color: white !important; }") as demo:
335
-
336
- gr.Markdown("## 🧠 SeoPlan2Article v3 β€” Enhanced SEO-Optimized Blog Generator")
337
- gr.Markdown("*Features: Human Tone Enforcement, Semantic SEO, Advanced Readability, Image Alt Texts, Personalized CTAs*")
338
-
339
- with gr.Accordion("πŸ”‘ API & SEO Plan", open=True):
340
- api_key_input_ui = gr.Textbox(label="Gemini API Key", type="password", placeholder="Paste your Gemini API key here...")
341
- primary_keyword_ui = gr.Textbox(label="Primary Keyword", placeholder="e.g., fermented garlic benefits")
342
- seo_plan_ui = gr.Textbox(label="SEO Plan or Outline", lines=10, placeholder="Paste detailed outline here...")
 
 
 
 
 
 
 
 
 
 
 
 
 
343
 
344
  with gr.Row():
345
- pov_ui = gr.Dropdown(label="πŸ“– Point of View", choices=["First Person (I/We)", "Second Person (You/Your)", "Third Person (He/She/It/They)"], value="Second Person (You/Your)")
346
- tone_ui = gr.Dropdown(label="🎨 Tone", choices=["Friendly", "Professional", "Witty", "Motivational", "Reassuring", "Curious"], value="Friendly")
347
- length_ui = gr.Dropdown(label="🧾 Length", choices=["Short", "Standard", "Long", "Very Long"], value="Standard")
348
- emotion_ui = gr.Dropdown(label="πŸ’¬ Emotion", choices=["Trust", "Excitement", "Curiosity", "Confidence", "Inspiration"], value="Confidence")
349
-
350
- with gr.Accordion("πŸ”— Keywords, Links, CTA", open=False):
351
- target_keywords_ui = gr.Textbox(label="Extra Keywords (optional)", placeholder="Comma-separated")
352
- links_to_include_ui = gr.Textbox(label="Internal/External Links (Optional)", placeholder="Format: Anchor: URL", lines=4)
353
- cta_text_ui = gr.Textbox(label="Custom Call to Action (Leave blank for auto-generated)", placeholder="e.g., Try it yourself and share your tips!")
354
-
355
- with gr.Accordion("βš™οΈ Enhanced Features", open=False):
356
- include_titles_ui = gr.Checkbox(label="Generate 3 SEO Title Variations", value=True)
357
- include_readability_ui = gr.Checkbox(label="Include Advanced Readability Analysis", value=True)
358
- include_alt_texts_ui = gr.Checkbox(label="Generate Image Alt Text Suggestions", value=True)
359
- include_faqs_ui = gr.Checkbox(label="Include FAQ Section", value=True)
360
-
361
- submit_btn = gr.Button("✨ Generate Enhanced Article", elem_id="generate_button")
362
- output_ui = gr.HTML("Your generated content will appear here...")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
363
 
364
- submit_btn.click(
365
- fn=generate_article,
366
  inputs=[
367
- api_key_input_ui, primary_keyword_ui, seo_plan_ui, pov_ui, tone_ui,
368
- length_ui, emotion_ui, include_titles_ui, include_readability_ui,
369
- target_keywords_ui, links_to_include_ui, cta_text_ui, include_alt_texts_ui, include_faqs_ui
370
  ],
371
- outputs=output_ui,
372
  )
373
 
374
- # --- Launch ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
375
  if __name__ == "__main__":
376
  demo.launch(debug=True, show_error=True)
 
4
  import re
5
  import requests
6
  from urllib.parse import urlparse
7
+ import json
8
+ import time
9
+ from typing import Dict, List, Tuple
10
+ import concurrent.futures
11
+
12
+ # --- Enhanced Keyword Research ---
13
+ class KeywordResearcher:
14
+ def __init__(self):
15
+ self.serp_api_key = None # Users can add their SERP API key for real data
16
+
17
+ def suggest_keywords(self, seed_keyword: str, model) -> Dict:
18
+ """Generate keyword suggestions with estimated metrics"""
19
+ prompt = f"""
20
+ Generate a comprehensive keyword research report for: "{seed_keyword}"
21
+
22
+ Provide 15-20 related keywords with estimated metrics:
23
+ - Primary keyword variations
24
+ - Long-tail keywords
25
+ - Question-based keywords
26
+ - Commercial intent keywords
27
+ - Informational intent keywords
28
+
29
+ Format as JSON:
30
+ {{
31
+ "primary_keywords": [
32
+ {{"keyword": "example", "search_volume": "high/medium/low", "difficulty": "easy/medium/hard", "intent": "informational/commercial/navigational"}}
33
+ ],
34
+ "long_tail": [...],
35
+ "questions": [...],
36
+ "commercial": [...]
37
+ }}
38
+ """
39
+
40
+ try:
41
+ response = model.generate_content(prompt)
42
+ # Parse JSON response
43
+ json_text = response.text.replace('```json', '').replace('```', '').strip()
44
+ return json.loads(json_text)
45
+ except:
46
+ return {
47
+ "primary_keywords": [
48
+ {"keyword": f"{seed_keyword} guide", "search_volume": "medium", "difficulty": "medium", "intent": "informational"},
49
+ {"keyword": f"{seed_keyword} tips", "search_volume": "medium", "difficulty": "easy", "intent": "informational"},
50
+ {"keyword": f"best {seed_keyword}", "search_volume": "high", "difficulty": "hard", "intent": "commercial"}
51
+ ],
52
+ "long_tail": [
53
+ {"keyword": f"how to use {seed_keyword} effectively", "search_volume": "low", "difficulty": "easy", "intent": "informational"}
54
+ ],
55
+ "questions": [
56
+ {"keyword": f"what is {seed_keyword}", "search_volume": "medium", "difficulty": "easy", "intent": "informational"}
57
+ ],
58
+ "commercial": [
59
+ {"keyword": f"{seed_keyword} service", "search_volume": "medium", "difficulty": "medium", "intent": "commercial"}
60
+ ]
61
+ }
62
+
63
+ # --- Competitor Analysis ---
64
+ class CompetitorAnalyzer:
65
+ def analyze_top_competitors(self, keyword: str, model) -> Dict:
66
+ """Analyze top competitors for content gaps"""
67
+ prompt = f"""
68
+ Analyze the top 5 competitors ranking for "{keyword}" and identify:
69
+
70
+ 1. Common content themes they cover
71
+ 2. Content gaps they're missing
72
+ 3. Average content length
73
+ 4. Heading structures they use
74
+ 5. Unique angles to differentiate our content
75
+
76
+ Format as structured analysis with actionable insights.
77
+ """
78
+
79
+ try:
80
+ response = model.generate_content(prompt)
81
+ return {
82
+ "analysis": response.text,
83
+ "content_gaps": self._extract_content_gaps(response.text),
84
+ "avg_length": "2000-3000 words",
85
+ "differentiation_angles": self._extract_angles(response.text)
86
+ }
87
+ except:
88
+ return {
89
+ "analysis": f"Competitors for '{keyword}' typically cover basic information. Opportunity to add more detailed examples and case studies.",
90
+ "content_gaps": ["Specific examples", "Step-by-step tutorials", "Common mistakes section"],
91
+ "avg_length": "2000-3000 words",
92
+ "differentiation_angles": ["Personal experience", "Updated statistics", "Unique framework"]
93
+ }
94
 
95
+ def _extract_content_gaps(self, text: str) -> List[str]:
96
+ """Extract content gaps from analysis"""
97
+ gaps = []
98
+ lines = text.split('\n')
99
+ for line in lines:
100
+ if 'gap' in line.lower() or 'missing' in line.lower() or 'opportunity' in line.lower():
101
+ gaps.append(line.strip('- ').strip())
102
+ return gaps[:5] if gaps else ["Advanced techniques", "Case studies", "Common mistakes"]
103
+
104
+ def _extract_angles(self, text: str) -> List[str]:
105
+ """Extract differentiation angles"""
106
+ angles = []
107
+ lines = text.split('\n')
108
+ for line in lines:
109
+ if 'unique' in line.lower() or 'different' in line.lower() or 'angle' in line.lower():
110
+ angles.append(line.strip('- ').strip())
111
+ return angles[:3] if angles else ["Personal experience", "Latest trends", "Actionable framework"]
112
+
113
+ # --- Content Outline Generator ---
114
+ class ContentOutliner:
115
+ def generate_seo_outline(self, keyword: str, keywords_data: Dict, competitor_data: Dict, model) -> str:
116
+ """Generate comprehensive SEO-optimized outline"""
117
+
118
+ # Extract top keywords for outline
119
+ all_keywords = []
120
+ for category in keywords_data.values():
121
+ if isinstance(category, list):
122
+ all_keywords.extend([k["keyword"] for k in category])
123
+
124
+ content_gaps = competitor_data.get("content_gaps", [])
125
+
126
+ prompt = f"""
127
+ Create a comprehensive SEO content outline for: "{keyword}"
128
+
129
+ REQUIREMENTS:
130
+ - Include H1, H2, H3 structure
131
+ - Integrate these keywords naturally: {', '.join(all_keywords[:10])}
132
+ - Address these content gaps: {', '.join(content_gaps)}
133
+ - Optimize for featured snippets
134
+ - Include FAQ section
135
+ - Add internal linking opportunities
136
+
137
+ OUTLINE FORMAT:
138
+ H1: [Compelling title with primary keyword]
139
+
140
+ Introduction (150-200 words)
141
+ - Hook with statistic or question
142
+ - Include primary keyword in first 100 words
143
+ - Promise what reader will learn
144
+
145
+ H2: [First main section]
146
+ H3: [Subsection]
147
+ H3: [Subsection]
148
+
149
+ [Continue with 4-6 main H2 sections]
150
+
151
+ H2: FAQ Section
152
+ - Question 1 (optimize for featured snippet)
153
+ - Question 2
154
+ - Question 3
155
+
156
+ Conclusion (100-150 words)
157
+ - Summarize key points
158
+ - Strong call to action
159
+
160
+ Add [INTERNAL LINK] and [IMAGE] suggestions throughout.
161
+ """
162
+
163
+ try:
164
+ response = model.generate_content(prompt)
165
+ return response.text
166
+ except:
167
+ return f"Error generating outline. Please check your API key and try again."
168
+
169
+ # --- Featured Snippet Optimizer ---
170
+ class SnippetOptimizer:
171
+ def optimize_for_snippets(self, content: str, questions: List[str], model) -> str:
172
+ """Optimize content sections for featured snippets"""
173
+
174
+ snippet_formats = {
175
+ "paragraph": "Answer in 40-50 words, clear and direct",
176
+ "list": "Format as numbered or bulleted list",
177
+ "table": "Present data in simple table format",
178
+ "steps": "Break down into clear step-by-step process"
179
+ }
180
+
181
+ optimized_sections = []
182
+
183
+ for question in questions[:5]: # Limit to top 5 questions
184
+ prompt = f"""
185
+ Optimize this answer for Google featured snippets:
186
+
187
+ Question: {question}
188
+
189
+ Requirements:
190
+ - Answer directly in first sentence
191
+ - Keep paragraph answers to 40-50 words
192
+ - Use clear, simple language
193
+ - Include the question keywords in the answer
194
+ - Format for easy scanning
195
+
196
+ Provide the optimized answer.
197
+ """
198
+
199
+ try:
200
+ response = model.generate_content(prompt)
201
+ optimized_sections.append(f"<h3>{question}</h3>\n<p>{response.text}</p>\n")
202
+ except:
203
+ optimized_sections.append(f"<h3>{question}</h3>\n<p>Answer optimized for featured snippets will appear here.</p>\n")
204
+
205
+ return "\n".join(optimized_sections)
206
+
207
+ # --- Smart Internal Linking ---
208
+ class InternalLinker:
209
+ def suggest_internal_links(self, content: str, keyword: str, model) -> List[Dict]:
210
+ """Suggest relevant internal links based on content"""
211
+
212
+ prompt = f"""
213
+ Analyze this content and suggest 5-7 internal linking opportunities:
214
+
215
+ Primary keyword: {keyword}
216
+ Content sample: {content[:1000]}...
217
+
218
+ For each suggestion, provide:
219
+ - Anchor text (natural, not over-optimized)
220
+ - Context where it should be placed
221
+ - Reason why it's valuable for SEO
222
+ - Suggested target page type
223
+
224
+ Format as actionable suggestions.
225
+ """
226
+
227
+ try:
228
+ response = model.generate_content(prompt)
229
+ # Parse suggestions into structured format
230
+ suggestions = []
231
+ lines = response.text.split('\n')
232
+ current_suggestion = {}
233
+
234
+ for line in lines:
235
+ if line.strip():
236
+ if 'anchor' in line.lower() or line.startswith('1.') or line.startswith('-'):
237
+ if current_suggestion:
238
+ suggestions.append(current_suggestion)
239
+ current_suggestion = {"text": line.strip()}
240
+ else:
241
+ if current_suggestion:
242
+ current_suggestion["text"] += " " + line.strip()
243
+
244
+ if current_suggestion:
245
+ suggestions.append(current_suggestion)
246
+
247
+ return suggestions[:7]
248
+ except:
249
+ return [
250
+ {"text": f"Link to related '{keyword}' resources in the introduction"},
251
+ {"text": f"Add contextual links to '{keyword}' tools or guides"},
252
+ {"text": f"Reference other '{keyword}' articles in conclusion"}
253
+ ]
254
+
255
+ # --- Enhanced Image Strategy ---
256
+ class ImageStrategist:
257
+ def create_image_strategy(self, outline: str, keyword: str, model) -> Dict:
258
+ """Create comprehensive image strategy"""
259
+
260
+ prompt = f"""
261
+ Based on this content outline, create a strategic image plan:
262
+
263
+ {outline}
264
+
265
+ For each major section, suggest:
266
+ 1. Image type (infographic, screenshot, photo, diagram, chart)
267
+ 2. Specific content description
268
+ 3. SEO-optimized alt text
269
+ 4. Placement strategy
270
+ 5. Size recommendations
271
+
272
+ Focus on images that:
273
+ - Support the content narrative
274
+ - Improve user engagement
275
+ - Optimize for image search
276
+ - Break up text effectively
277
+
278
+ Primary keyword: {keyword}
279
+ """
280
+
281
+ try:
282
+ response = model.generate_content(prompt)
283
+ return {
284
+ "strategy": response.text,
285
+ "image_count": self._count_suggested_images(response.text),
286
+ "alt_texts": self._extract_alt_texts(response.text, keyword)
287
+ }
288
+ except:
289
+ return {
290
+ "strategy": f"Add 3-5 relevant images throughout the article about {keyword}",
291
+ "image_count": 4,
292
+ "alt_texts": [
293
+ f"Comprehensive guide to {keyword} - infographic",
294
+ f"Step-by-step {keyword} process diagram",
295
+ f"Benefits of {keyword} - visual comparison",
296
+ f"Common {keyword} mistakes to avoid"
297
+ ]
298
+ }
299
 
300
+ def _count_suggested_images(self, text: str) -> int:
301
+ """Count suggested images in strategy"""
302
+ return min(text.lower().count('image') + text.lower().count('infographic') + text.lower().count('diagram'), 8)
303
 
304
+ def _extract_alt_texts(self, text: str, keyword: str) -> List[str]:
305
+ """Extract alt text suggestions"""
306
+ alt_texts = []
307
+ lines = text.split('\n')
308
+ for line in lines:
309
+ if 'alt' in line.lower() or 'description' in line.lower():
310
+ alt_texts.append(line.strip('- ').strip())
311
+
312
+ if not alt_texts:
313
+ alt_texts = [
314
+ f"Complete {keyword} guide infographic",
315
+ f"Step-by-step {keyword} tutorial",
316
+ f"{keyword} benefits comparison chart",
317
+ f"Real-world {keyword} examples"
318
+ ]
319
+
320
+ return alt_texts[:6]
321
+
322
+ # --- Main Enhanced Generator ---
323
+ def generate_complete_seo_content(api_key, seed_keyword, custom_outline, pov, tone, length, emotion,
324
+ include_research, include_competitor, include_outline, include_snippets,
325
+ include_linking, include_images, target_keywords, custom_cta):
326
 
327
+ if not api_key or not seed_keyword:
328
+ return "Please provide API key and seed keyword to generate content."
329
+
330
+ try:
331
+ genai.configure(api_key=api_key)
332
+ model = genai.GenerativeModel('gemini-1.5-flash')
333
+ except Exception as e:
334
+ return f"Error configuring API: {str(e)}"
335
 
336
+ # Initialize components
337
+ researcher = KeywordResearcher()
338
+ competitor_analyzer = CompetitorAnalyzer()
339
+ outliner = ContentOutliner()
340
+ snippet_optimizer = SnippetOptimizer()
341
+ internal_linker = InternalLinker()
342
+ image_strategist = ImageStrategist()
 
343
 
344
+ results = []
 
 
345
 
346
+ # Step 1: Keyword Research
347
+ if include_research:
348
+ results.append("πŸ” **STEP 1: KEYWORD RESEARCH**")
349
+ keywords_data = researcher.suggest_keywords(seed_keyword, model)
350
+
351
+ # Format keyword research results
352
+ results.append("**Primary Keywords:**")
353
+ for kw in keywords_data.get("primary_keywords", [])[:5]:
354
+ results.append(f"β€’ {kw['keyword']} (Volume: {kw['search_volume']}, Difficulty: {kw['difficulty']})")
355
+
356
+ results.append("\n**Long-tail Keywords:**")
357
+ for kw in keywords_data.get("long_tail", [])[:3]:
358
+ results.append(f"β€’ {kw['keyword']} (Intent: {kw['intent']})")
359
+
360
+ results.append("\n**Question Keywords:**")
361
+ for kw in keywords_data.get("questions", [])[:3]:
362
+ results.append(f"β€’ {kw['keyword']}")
363
+
364
+ results.append("\n" + "="*50 + "\n")
365
  else:
366
+ keywords_data = {"primary_keywords": [{"keyword": seed_keyword, "search_volume": "medium", "difficulty": "medium", "intent": "informational"}]}
367
 
368
+ # Step 2: Competitor Analysis
369
+ if include_competitor:
370
+ results.append("πŸ† **STEP 2: COMPETITOR ANALYSIS**")
371
+ competitor_data = competitor_analyzer.analyze_top_competitors(seed_keyword, model)
372
+ results.append(competitor_data["analysis"])
373
+ results.append("\n**Content Gaps Identified:**")
374
+ for gap in competitor_data["content_gaps"]:
375
+ results.append(f"β€’ {gap}")
376
+ results.append("\n" + "="*50 + "\n")
377
+ else:
378
+ competitor_data = {"content_gaps": [], "analysis": ""}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
 
380
+ # Step 3: Content Outline
381
+ if include_outline:
382
+ results.append("πŸ“‹ **STEP 3: SEO-OPTIMIZED OUTLINE**")
383
+ if custom_outline.strip():
384
+ outline = custom_outline
385
+ else:
386
+ outline = outliner.generate_seo_outline(seed_keyword, keywords_data, competitor_data, model)
387
+ results.append(outline)
388
+ results.append("\n" + "="*50 + "\n")
389
+ else:
390
+ outline = custom_outline if custom_outline.strip() else f"Article about {seed_keyword}"
 
 
391
 
392
+ # Step 4: Generate Main Content
393
+ results.append("✍️ **STEP 4: FULL ARTICLE CONTENT**")
 
 
 
 
 
394
 
395
+ # Extract all keywords for content generation
396
+ all_keywords = [seed_keyword]
397
+ if target_keywords:
398
+ all_keywords.extend([k.strip() for k in target_keywords.split(',')])
399
 
400
+ for category in keywords_data.values():
401
+ if isinstance(category, list):
402
+ all_keywords.extend([k["keyword"] for k in category[:2]]) # Top 2 from each category
403
 
404
+ # Enhanced content generation prompt
405
+ content_prompt = f"""
406
+ Write a comprehensive, SEO-optimized blog post based on this outline:
407
 
408
+ {outline}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
409
 
410
+ REQUIREMENTS:
411
+ - Primary keyword: "{seed_keyword}"
412
+ - Integrate these keywords naturally: {', '.join(all_keywords[:15])}
413
+ - Tone: {tone}, POV: {pov}, Emotion: {emotion}
414
+ - Length: {length}
415
+ - Write in genuinely human style - avoid AI phrases
416
+ - Use HTML formatting for WordPress
417
+ - Include specific examples and actionable advice
418
+ - Optimize for readability with short paragraphs
419
+ - Add [INTERNAL LINK] placeholders where relevant
420
+ - Add [IMAGE: description] placeholders for visuals
421
+
422
+ Content should be comprehensive, engaging, and provide real value to readers.
423
+ Make it feel like it's written by an expert who genuinely cares about helping the reader.
424
+ """
425
 
426
  try:
427
+ content_response = model.generate_content(content_prompt)
428
+ main_content = content_response.text
429
+ results.append(main_content)
430
  except Exception as e:
431
+ results.append(f"Error generating main content: {str(e)}")
432
+ main_content = f"Content about {seed_keyword} would appear here."
 
 
 
433
 
434
+ results.append("\n" + "="*50 + "\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
435
 
436
+ # Step 5: Featured Snippet Optimization
437
+ if include_snippets:
438
+ results.append("🎯 **STEP 5: FEATURED SNIPPET OPTIMIZATION**")
439
+ questions = [kw["keyword"] for kw in keywords_data.get("questions", [])]
440
+ if not questions:
441
+ questions = [f"What is {seed_keyword}?", f"How to use {seed_keyword}?", f"Benefits of {seed_keyword}?"]
442
+
443
+ snippet_content = snippet_optimizer.optimize_for_snippets(main_content, questions, model)
444
+ results.append("**FAQ Section Optimized for Featured Snippets:**")
445
+ results.append(snippet_content)
446
+ results.append("\n" + "="*50 + "\n")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
447
 
448
+ # Step 6: Internal Linking Strategy
449
+ if include_linking:
450
+ results.append("πŸ”— **STEP 6: INTERNAL LINKING STRATEGY**")
451
+ link_suggestions = internal_linker.suggest_internal_links(main_content, seed_keyword, model)
452
+ results.append("**Suggested Internal Links:**")
453
+ for i, suggestion in enumerate(link_suggestions, 1):
454
+ results.append(f"{i}. {suggestion['text']}")
455
+ results.append("\n" + "="*50 + "\n")
 
 
 
 
 
 
 
 
 
 
456
 
457
+ # Step 7: Image Strategy
458
+ if include_images:
459
+ results.append("πŸ–ΌοΈ **STEP 7: IMAGE STRATEGY**")
460
+ image_strategy = image_strategist.create_image_strategy(outline, seed_keyword, model)
461
+ results.append(f"**Recommended Images: {image_strategy['image_count']}**")
462
+ results.append(image_strategy["strategy"])
463
+ results.append("\n**Optimized Alt Texts:**")
464
+ for i, alt_text in enumerate(image_strategy["alt_texts"], 1):
465
+ results.append(f"{i}. {alt_text}")
466
+ results.append("\n" + "="*50 + "\n")
467
+
468
+ # Step 8: Meta Data
469
+ results.append("πŸ“Š **STEP 8: SEO META DATA**")
470
+
471
+ # Generate meta title and description
472
+ meta_prompt = f"""
473
+ Create SEO-optimized meta data for this content:
474
+
475
+ Primary keyword: {seed_keyword}
476
+ Content summary: {main_content[:500]}...
477
+
478
+ Generate:
479
+ 1. Meta title (under 60 characters, include primary keyword)
480
+ 2. Meta description (under 160 characters, compelling and click-worthy)
481
+ 3. 3 alternative title variations
482
+ """
483
+
484
+ try:
485
+ meta_response = model.generate_content(meta_prompt)
486
+ results.append(meta_response.text)
487
+ except:
488
+ results.append(f"**Meta Title:** {seed_keyword.title()} - Complete Guide")
489
+ results.append(f"**Meta Description:** Discover everything about {seed_keyword} in this comprehensive guide. Get actionable tips and expert insights.")
490
+
491
+ # Final readability analysis
492
+ word_count = len(main_content.split())
493
+ flesch_score = textstat.flesch_reading_ease(main_content) if main_content else 0
494
+
495
+ results.append(f"\n**Content Analysis:**")
496
+ results.append(f"β€’ Word Count: {word_count}")
497
+ results.append(f"β€’ Readability Score: {flesch_score:.1f}")
498
+ results.append(f"β€’ Keywords Integrated: {len(all_keywords)}")
499
+
500
+ return "\n".join(results)
501
+
502
+ # --- Gradio Interface ---
503
+ with gr.Blocks(css="""
504
+ #generate_button {
505
+ background: linear-gradient(45deg, #10b981, #059669) !important;
506
+ color: white !important;
507
+ font-weight: bold !important;
508
+ border: none !important;
509
+ }
510
+ .gradio-container { max-width: 1200px !important; }
511
+ .step-header { color: #059669; font-weight: bold; }
512
+ """) as demo:
513
+
514
+ gr.Markdown("# πŸš€ SeoPlan2Article v4 - Complete SEO Content System")
515
+ gr.Markdown("*Full workflow: Keyword Research β†’ Competitor Analysis β†’ Content Outline β†’ Article Generation β†’ SEO Optimization β†’ Link Strategy β†’ Image Planning*")
516
+
517
+ with gr.Accordion("πŸ”‘ API Configuration", open=True):
518
+ api_key_input = gr.Textbox(
519
+ label="Gemini API Key",
520
+ type="password",
521
+ placeholder="Enter your Gemini API key..."
522
+ )
523
+ seed_keyword_input = gr.Textbox(
524
+ label="Seed Keyword",
525
+ placeholder="e.g., sustainable gardening tips",
526
+ info="Primary keyword for research and content generation"
527
+ )
528
+
529
+ with gr.Accordion("πŸ“‹ Content Outline (Optional)", open=False):
530
+ custom_outline_input = gr.Textbox(
531
+ label="Custom Content Outline",
532
+ lines=8,
533
+ placeholder="Leave blank to auto-generate, or paste your outline here...",
534
+ info="If provided, this will be used instead of auto-generated outline"
535
+ )
536
 
537
  with gr.Row():
538
+ with gr.Column():
539
+ pov_input = gr.Dropdown(
540
+ label="πŸ“– Point of View",
541
+ choices=["First Person (I/We)", "Second Person (You/Your)", "Third Person (He/She/It/They)"],
542
+ value="Second Person (You/Your)"
543
+ )
544
+ tone_input = gr.Dropdown(
545
+ label="🎨 Tone",
546
+ choices=["Friendly", "Professional", "Witty", "Motivational", "Reassuring", "Authoritative"],
547
+ value="Professional"
548
+ )
549
+ with gr.Column():
550
+ length_input = gr.Dropdown(
551
+ label="πŸ“ Article Length",
552
+ choices=["Short (800-1200)", "Standard (1500-2500)", "Long (2500-4000)", "Very Long (4000+)"],
553
+ value="Standard (1500-2500)"
554
+ )
555
+ emotion_input = gr.Dropdown(
556
+ label="πŸ’­ Emotional Tone",
557
+ choices=["Trust", "Excitement", "Curiosity", "Confidence", "Inspiration", "Urgency"],
558
+ value="Trust"
559
+ )
560
+
561
+ with gr.Accordion("πŸ”§ Workflow Steps", open=True):
562
+ gr.Markdown("Select which steps to include in your SEO content workflow:")
563
+
564
+ with gr.Row():
565
+ include_research = gr.Checkbox(label="πŸ” Keyword Research", value=True)
566
+ include_competitor = gr.Checkbox(label="πŸ† Competitor Analysis", value=True)
567
+ include_outline = gr.Checkbox(label="πŸ“‹ Auto-Generate Outline", value=True)
568
+
569
+ with gr.Row():
570
+ include_snippets = gr.Checkbox(label="🎯 Featured Snippet Optimization", value=True)
571
+ include_linking = gr.Checkbox(label="πŸ”— Internal Link Strategy", value=True)
572
+ include_images = gr.Checkbox(label="πŸ–ΌοΈ Image Strategy", value=True)
573
+
574
+ with gr.Accordion("βš™οΈ Additional Options", open=False):
575
+ target_keywords_input = gr.Textbox(
576
+ label="Additional Target Keywords",
577
+ placeholder="Comma-separated keywords to include",
578
+ info="Optional: Add specific keywords you want to target"
579
+ )
580
+ custom_cta_input = gr.Textbox(
581
+ label="Custom Call-to-Action",
582
+ placeholder="Leave blank for auto-generated CTA",
583
+ info="Optional: Specify your preferred call-to-action"
584
+ )
585
+
586
+ generate_btn = gr.Button("πŸš€ Generate Complete SEO Content System", elem_id="generate_button", size="lg")
587
+
588
+ output = gr.Markdown("Your complete SEO content analysis will appear here...")
589
 
590
+ generate_btn.click(
591
+ fn=generate_complete_seo_content,
592
  inputs=[
593
+ api_key_input, seed_keyword_input, custom_outline_input, pov_input, tone_input,
594
+ length_input, emotion_input, include_research, include_competitor, include_outline,
595
+ include_snippets, include_linking, include_images, target_keywords_input, custom_cta_input
596
  ],
597
+ outputs=output
598
  )
599
 
600
+ gr.Markdown("""
601
+ ## 🎯 What This System Does:
602
+
603
+ **Complete SEO Workflow Coverage:**
604
+ 1. **Keyword Research** - Find primary, long-tail, and question keywords with intent analysis
605
+ 2. **Competitor Analysis** - Identify content gaps and differentiation opportunities
606
+ 3. **Content Outline** - Generate SEO-optimized H1/H2/H3 structure
607
+ 4. **Article Generation** - Write comprehensive, human-like content
608
+ 5. **Featured Snippet Optimization** - Format FAQs and answers for Google snippets
609
+ 6. **Internal Link Strategy** - Suggest relevant internal linking opportunities
610
+ 7. **Image Strategy** - Plan visual content with SEO-optimized alt texts
611
+ 8. **Meta Data** - Generate optimized titles and descriptions
612
+
613
+ **Enhanced Features:**
614
+ - Human tone enforcement (avoid AI-like phrases)
615
+ - Semantic keyword integration
616
+ - Competitor content gap analysis
617
+ - Featured snippet formatting
618
+ - Strategic image placement
619
+ - Internal linking suggestions
620
+ - Complete meta data optimization
621
+ """)
622
+
623
  if __name__ == "__main__":
624
  demo.launch(debug=True, show_error=True)