mroccuper commited on
Commit
196c8fe
Β·
verified Β·
1 Parent(s): 2ccda21

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +240 -34
app.py CHANGED
@@ -9,7 +9,45 @@ 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
@@ -204,10 +242,41 @@ class SnippetOptimizer:
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:
@@ -215,13 +284,16 @@ class InternalLinker:
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:
@@ -251,6 +323,26 @@ class InternalLinker:
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:
@@ -322,7 +414,7 @@ class ImageStrategist:
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."
@@ -338,21 +430,58 @@ def generate_complete_seo_content(api_key, seed_keyword, custom_outline, pov, to
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']})")
@@ -364,6 +493,8 @@ def generate_complete_seo_content(api_key, seed_keyword, custom_outline, pov, to
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:
@@ -394,13 +525,18 @@ def generate_complete_seo_content(api_key, seed_keyword, custom_outline, pov, to
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:
@@ -409,18 +545,26 @@ def generate_complete_seo_content(api_key, seed_keyword, custom_outline, pov, to
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:
@@ -447,9 +591,24 @@ def generate_complete_seo_content(api_key, seed_keyword, custom_outline, pov, to
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")
@@ -473,12 +632,15 @@ def generate_complete_seo_content(api_key, seed_keyword, custom_outline, pov, to
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:
@@ -488,14 +650,30 @@ def generate_complete_seo_content(api_key, seed_keyword, custom_outline, pov, to
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
 
@@ -571,12 +749,23 @@ with gr.Blocks(css="""
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",
@@ -592,7 +781,8 @@ with gr.Blocks(css="""
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
  )
@@ -601,14 +791,29 @@ with gr.Blocks(css="""
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)
@@ -616,8 +821,9 @@ with gr.Blocks(css="""
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__":
 
9
  from typing import Dict, List, Tuple
10
  import concurrent.futures
11
 
12
+ # --- Manual Keywords Processor ---
13
+ class ManualKeywordProcessor:
14
+ def parse_manual_keywords(self, manual_keywords: str) -> List[str]:
15
+ """Parse and clean manual target keywords"""
16
+ if not manual_keywords.strip():
17
+ return []
18
+
19
+ keywords = []
20
+ # Split by comma, semicolon, or newline
21
+ raw_keywords = re.split(r'[,;\n]', manual_keywords)
22
+
23
+ for keyword in raw_keywords:
24
+ cleaned = keyword.strip().lower()
25
+ if cleaned and len(cleaned) > 2: # Minimum keyword length
26
+ keywords.append(cleaned)
27
+
28
+ return list(set(keywords)) # Remove duplicates
29
+
30
+ def integrate_manual_keywords(self, auto_keywords: Dict, manual_keywords: List[str]) -> Dict:
31
+ """Integrate manual keywords with auto-generated ones"""
32
+ # Add manual keywords to primary keywords list
33
+ manual_keyword_objects = []
34
+ for kw in manual_keywords:
35
+ manual_keyword_objects.append({
36
+ "keyword": kw,
37
+ "search_volume": "manual",
38
+ "difficulty": "unknown",
39
+ "intent": "targeted"
40
+ })
41
+
42
+ # Merge with existing keywords
43
+ integrated = auto_keywords.copy()
44
+
45
+ if "manual_targets" not in integrated:
46
+ integrated["manual_targets"] = []
47
+
48
+ integrated["manual_targets"] = manual_keyword_objects
49
+
50
+ return integrated
51
  class KeywordResearcher:
52
  def __init__(self):
53
  self.serp_api_key = None # Users can add their SERP API key for real data
 
242
 
243
  return "\n".join(optimized_sections)
244
 
245
+ # --- Enhanced Link Management ---
246
+ class LinkManager:
247
+ def parse_manual_links(self, links_input: str) -> Dict:
248
+ """Parse manual internal and external links"""
249
+ internal_links = []
250
+ external_links = []
251
+
252
+ if not links_input.strip():
253
+ return {"internal": [], "external": []}
254
+
255
+ lines = links_input.strip().split('\n')
256
+ for line in lines:
257
+ if ':' in line:
258
+ anchor_text, url = line.split(':', 1)
259
+ anchor_text = anchor_text.strip()
260
+ url = url.strip()
261
+
262
+ # Determine if internal or external
263
+ if url.startswith('http'):
264
+ # Check if it's same domain (simplified check)
265
+ if 'website.com' in url or 'yourdomain.com' in url or url.startswith('/'):
266
+ internal_links.append({"anchor": anchor_text, "url": url})
267
+ else:
268
+ external_links.append({"anchor": anchor_text, "url": url})
269
+ else:
270
+ # Assume internal if no http
271
+ internal_links.append({"anchor": anchor_text, "url": url})
272
+
273
+ return {"internal": internal_links, "external": external_links}
274
+
275
+ def suggest_internal_links(self, content: str, keyword: str, manual_links: Dict, model) -> List[Dict]:
276
+ """Suggest relevant internal links based on content and manual links"""
277
+
278
+ # Include manual internal links in suggestions
279
+ existing_internal = manual_links.get("internal", [])
280
 
281
  prompt = f"""
282
  Analyze this content and suggest 5-7 internal linking opportunities:
 
284
  Primary keyword: {keyword}
285
  Content sample: {content[:1000]}...
286
 
287
+ Already provided internal links:
288
+ {chr(10).join([f"- {link['anchor']}: {link['url']}" for link in existing_internal])}
289
+
290
+ For each NEW suggestion, provide:
291
  - Anchor text (natural, not over-optimized)
292
  - Context where it should be placed
293
  - Reason why it's valuable for SEO
294
  - Suggested target page type
295
 
296
+ Format as actionable suggestions. Don't repeat the existing links above.
297
  """
298
 
299
  try:
 
323
  {"text": f"Add contextual links to '{keyword}' tools or guides"},
324
  {"text": f"Reference other '{keyword}' articles in conclusion"}
325
  ]
326
+
327
+ def format_links_for_content(self, manual_links: Dict) -> str:
328
+ """Format manual links for inclusion in content"""
329
+ formatted_links = []
330
+
331
+ # Internal links
332
+ internal_links = manual_links.get("internal", [])
333
+ if internal_links:
334
+ formatted_links.append("**Internal Links to Include:**")
335
+ for link in internal_links:
336
+ formatted_links.append(f'<a href="{link["url"]}">{link["anchor"]}</a>')
337
+
338
+ # External links
339
+ external_links = manual_links.get("external", [])
340
+ if external_links:
341
+ formatted_links.append("\n**External Links to Include:**")
342
+ for link in external_links:
343
+ formatted_links.append(f'<a href="{link["url"]}" target="_blank" rel="noopener">{link["anchor"]}</a>')
344
+
345
+ return "\n".join(formatted_links)
346
 
347
  # --- Enhanced Image Strategy ---
348
  class ImageStrategist:
 
414
  # --- Main Enhanced Generator ---
415
  def generate_complete_seo_content(api_key, seed_keyword, custom_outline, pov, tone, length, emotion,
416
  include_research, include_competitor, include_outline, include_snippets,
417
+ include_linking, include_images, manual_target_keywords, manual_links_input, custom_cta):
418
 
419
  if not api_key or not seed_keyword:
420
  return "Please provide API key and seed keyword to generate content."
 
430
  competitor_analyzer = CompetitorAnalyzer()
431
  outliner = ContentOutliner()
432
  snippet_optimizer = SnippetOptimizer()
433
+ link_manager = LinkManager()
434
  image_strategist = ImageStrategist()
435
+ keyword_processor = ManualKeywordProcessor()
436
 
437
  results = []
438
 
439
+ # Process manual keywords
440
+ manual_keywords = keyword_processor.parse_manual_keywords(manual_target_keywords)
441
+ if manual_keywords:
442
+ results.append("🎯 **MANUAL TARGET KEYWORDS PROCESSED**")
443
+ results.append("**Your Specified Keywords:**")
444
+ for kw in manual_keywords:
445
+ results.append(f"β€’ {kw}")
446
+ results.append("\n" + "="*50 + "\n")
447
+
448
+ # Process manual links
449
+ parsed_links = link_manager.parse_manual_links(manual_links_input)
450
+ if parsed_links["internal"] or parsed_links["external"]:
451
+ results.append("πŸ”— **MANUAL LINKS PROCESSED**")
452
+
453
+ if parsed_links["internal"]:
454
+ results.append("**Internal Links:**")
455
+ for link in parsed_links["internal"]:
456
+ results.append(f"β€’ {link['anchor']} β†’ {link['url']}")
457
+
458
+ if parsed_links["external"]:
459
+ results.append("**External Links:**")
460
+ for link in parsed_links["external"]:
461
+ results.append(f"β€’ {link['anchor']} β†’ {link['url']}")
462
+
463
+ results.append("\n" + "="*50 + "\n")
464
+
465
  # Step 1: Keyword Research
466
  if include_research:
467
  results.append("πŸ” **STEP 1: KEYWORD RESEARCH**")
468
  keywords_data = researcher.suggest_keywords(seed_keyword, model)
469
 
470
+ # Integrate manual keywords
471
+ if manual_keywords:
472
+ keywords_data = keyword_processor.integrate_manual_keywords(keywords_data, manual_keywords)
473
+
474
  # Format keyword research results
475
  results.append("**Primary Keywords:**")
476
  for kw in keywords_data.get("primary_keywords", [])[:5]:
477
  results.append(f"β€’ {kw['keyword']} (Volume: {kw['search_volume']}, Difficulty: {kw['difficulty']})")
478
 
479
+ # Show manual keywords separately
480
+ if manual_keywords:
481
+ results.append("\n**Manual Target Keywords:**")
482
+ for kw in keywords_data.get("manual_targets", []):
483
+ results.append(f"β€’ {kw['keyword']} (Manual Target)")
484
+
485
  results.append("\n**Long-tail Keywords:**")
486
  for kw in keywords_data.get("long_tail", [])[:3]:
487
  results.append(f"β€’ {kw['keyword']} (Intent: {kw['intent']})")
 
493
  results.append("\n" + "="*50 + "\n")
494
  else:
495
  keywords_data = {"primary_keywords": [{"keyword": seed_keyword, "search_volume": "medium", "difficulty": "medium", "intent": "informational"}]}
496
+ if manual_keywords:
497
+ keywords_data = keyword_processor.integrate_manual_keywords(keywords_data, manual_keywords)
498
 
499
  # Step 2: Competitor Analysis
500
  if include_competitor:
 
525
 
526
  # Extract all keywords for content generation
527
  all_keywords = [seed_keyword]
 
 
528
 
529
+ # Add manual keywords first (highest priority)
530
+ all_keywords.extend(manual_keywords)
531
+
532
+ # Add auto-generated keywords
533
  for category in keywords_data.values():
534
  if isinstance(category, list):
535
  all_keywords.extend([k["keyword"] for k in category[:2]]) # Top 2 from each category
536
 
537
+ # Prepare manual links for content integration
538
+ manual_links_formatted = link_manager.format_links_for_content(parsed_links)
539
+
540
  # Enhanced content generation prompt
541
  content_prompt = f"""
542
  Write a comprehensive, SEO-optimized blog post based on this outline:
 
545
 
546
  REQUIREMENTS:
547
  - Primary keyword: "{seed_keyword}"
548
+ - MUST integrate these manual target keywords naturally: {', '.join(manual_keywords) if manual_keywords else 'None specified'}
549
+ - Also include these keywords: {', '.join(all_keywords[len(manual_keywords)+1:15])}
550
  - Tone: {tone}, POV: {pov}, Emotion: {emotion}
551
  - Length: {length}
552
  - Write in genuinely human style - avoid AI phrases
553
  - Use HTML formatting for WordPress
554
  - Include specific examples and actionable advice
555
  - Optimize for readability with short paragraphs
556
+
557
+ LINKS TO INTEGRATE:
558
+ {manual_links_formatted if manual_links_formatted else 'No manual links provided'}
559
+
560
+ Instructions for links:
561
+ - Naturally integrate the provided internal and external links where contextually relevant
562
+ - Add [INTERNAL LINK OPPORTUNITY] markers for additional internal link suggestions
563
  - Add [IMAGE: description] placeholders for visuals
564
 
565
  Content should be comprehensive, engaging, and provide real value to readers.
566
  Make it feel like it's written by an expert who genuinely cares about helping the reader.
567
+ Prioritize the manual target keywords - they should appear naturally throughout the content.
568
  """
569
 
570
  try:
 
591
 
592
  # Step 6: Internal Linking Strategy
593
  if include_linking:
594
+ results.append("πŸ”— **STEP 6: LINKING STRATEGY**")
595
+
596
+ # Show processed manual links
597
+ if parsed_links["internal"] or parsed_links["external"]:
598
+ results.append("**Your Manual Links (Already Integrated):**")
599
+ if parsed_links["internal"]:
600
+ results.append("*Internal Links:*")
601
+ for link in parsed_links["internal"]:
602
+ results.append(f"β€’ {link['anchor']} β†’ {link['url']}")
603
+ if parsed_links["external"]:
604
+ results.append("*External Links:*")
605
+ for link in parsed_links["external"]:
606
+ results.append(f"β€’ {link['anchor']} β†’ {link['url']}")
607
+ results.append("")
608
+
609
+ # Suggest additional internal links
610
+ link_suggestions = link_manager.suggest_internal_links(main_content, seed_keyword, parsed_links, model)
611
+ results.append("**Additional Internal Link Suggestions:**")
612
  for i, suggestion in enumerate(link_suggestions, 1):
613
  results.append(f"{i}. {suggestion['text']}")
614
  results.append("\n" + "="*50 + "\n")
 
632
  Create SEO-optimized meta data for this content:
633
 
634
  Primary keyword: {seed_keyword}
635
+ Manual target keywords: {', '.join(manual_keywords) if manual_keywords else 'None'}
636
  Content summary: {main_content[:500]}...
637
 
638
  Generate:
639
+ 1. Meta title (under 60 characters, include primary keyword and/or manual keywords)
640
  2. Meta description (under 160 characters, compelling and click-worthy)
641
  3. 3 alternative title variations
642
+
643
+ Prioritize the manual target keywords in meta data if provided.
644
  """
645
 
646
  try:
 
650
  results.append(f"**Meta Title:** {seed_keyword.title()} - Complete Guide")
651
  results.append(f"**Meta Description:** Discover everything about {seed_keyword} in this comprehensive guide. Get actionable tips and expert insights.")
652
 
653
+ # Final analysis including manual keywords
654
  word_count = len(main_content.split())
655
  flesch_score = textstat.flesch_reading_ease(main_content) if main_content else 0
656
 
657
+ # Count manual keyword usage
658
+ manual_keyword_usage = {}
659
+ if manual_keywords:
660
+ for kw in manual_keywords:
661
+ count = main_content.lower().count(kw.lower())
662
+ manual_keyword_usage[kw] = count
663
+
664
  results.append(f"\n**Content Analysis:**")
665
  results.append(f"β€’ Word Count: {word_count}")
666
  results.append(f"β€’ Readability Score: {flesch_score:.1f}")
667
+ results.append(f"β€’ Total Keywords Integrated: {len(all_keywords)}")
668
+
669
+ if manual_keyword_usage:
670
+ results.append(f"β€’ Manual Keywords Usage:")
671
+ for kw, count in manual_keyword_usage.items():
672
+ density = round((count / word_count) * 100, 2) if word_count > 0 else 0
673
+ results.append(f" - '{kw}': {count} times ({density}% density)")
674
+
675
+ if parsed_links["internal"] or parsed_links["external"]:
676
+ results.append(f"β€’ Manual Links Integrated: {len(parsed_links['internal']) + len(parsed_links['external'])}")
677
 
678
  return "\n".join(results)
679
 
 
749
  include_linking = gr.Checkbox(label="πŸ”— Internal Link Strategy", value=True)
750
  include_images = gr.Checkbox(label="πŸ–ΌοΈ Image Strategy", value=True)
751
 
752
+ with gr.Accordion("βš™οΈ Manual Targeting & Links", open=True):
753
+ gr.Markdown("### 🎯 Manual Target Keywords")
754
+ manual_target_keywords_input = gr.Textbox(
755
+ label="Manual Target Keywords",
756
+ placeholder="fermented pickle, homemade fermentation, pickle fermentation process",
757
+ lines=3,
758
+ info="Comma-separated keywords you specifically want to target. These get PRIORITY in content generation."
759
+ )
760
+
761
+ gr.Markdown("### πŸ”— Manual Internal & External Links")
762
+ manual_links_input = gr.Textbox(
763
+ label="Links to Include",
764
+ placeholder="fermented pickle guide: https://www.website.com/fermented-pickle-at-home\nhealthy fermentation: /internal-page\nfermentation benefits: https://external-authority.com/benefits",
765
+ lines=6,
766
+ info="Format: 'Anchor Text: URL' (one per line). Use full URLs for external, relative paths for internal."
767
  )
768
+
769
  custom_cta_input = gr.Textbox(
770
  label="Custom Call-to-Action",
771
  placeholder="Leave blank for auto-generated CTA",
 
781
  inputs=[
782
  api_key_input, seed_keyword_input, custom_outline_input, pov_input, tone_input,
783
  length_input, emotion_input, include_research, include_competitor, include_outline,
784
+ include_snippets, include_linking, include_images, manual_target_keywords_input,
785
+ manual_links_input, custom_cta_input
786
  ],
787
  outputs=output
788
  )
 
791
  ## 🎯 What This System Does:
792
 
793
  **Complete SEO Workflow Coverage:**
794
+ 1. **Manual Targeting** - Specify exact keywords and links you want prioritized
795
+ 2. **Keyword Research** - Find primary, long-tail, and question keywords with intent analysis
796
+ 3. **Competitor Analysis** - Identify content gaps and differentiation opportunities
797
+ 4. **Content Outline** - Generate SEO-optimized H1/H2/H3 structure
798
+ 5. **Article Generation** - Write comprehensive, human-like content with your manual targets
799
+ 6. **Featured Snippet Optimization** - Format FAQs and answers for Google snippets
800
+ 7. **Link Strategy** - Integrate your manual links + suggest additional opportunities
801
+ 8. **Image Strategy** - Plan visual content with SEO-optimized alt texts
802
+ 9. **Meta Data** - Generate optimized titles and descriptions
803
+
804
+ **πŸ†• NEW Manual Targeting Features:**
805
+ - **Priority Keywords**: Your manual keywords get highest priority in content
806
+ - **Smart Link Integration**: Automatically integrates your internal/external links contextually
807
+ - **Link Classification**: Automatically detects internal vs external links
808
+ - **Usage Tracking**: Shows exactly how many times your manual keywords appear
809
+ - **Density Analysis**: Calculates keyword density for your target terms
810
+
811
+ **Link Format Examples:**
812
+ ```
813
+ fermented pickle guide: https://www.website.com/fermented-pickle-at-home
814
+ healthy fermentation: /internal-fermentation-page
815
+ scientific study: https://pubmed.ncbi.nlm.nih.gov/study-link
816
+ ```
817
 
818
  **Enhanced Features:**
819
  - Human tone enforcement (avoid AI-like phrases)
 
821
  - Competitor content gap analysis
822
  - Featured snippet formatting
823
  - Strategic image placement
824
+ - Manual + automatic linking strategy
825
  - Complete meta data optimization
826
+ - Priority keyword tracking
827
  """)
828
 
829
  if __name__ == "__main__":