|
|
|
|
|
""" |
|
|
SEO Blog Generator with Gemini 1.5 Pro API |
|
|
Enhanced: Internal Links + Extra Keywords + HTML File Download + WordPress Optimization |
|
|
New Features: SEO Score, Title Variations, Readability Analysis, Social Media Snippets, Citations, Uniqueness Check |
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
import gradio as gr |
|
|
import requests |
|
|
import markdown2 |
|
|
import os |
|
|
import re |
|
|
from datetime import datetime |
|
|
|
|
|
class BlogGenerator: |
|
|
@staticmethod |
|
|
def clean_output(content): |
|
|
return re.sub(r'```html|```', '', content).strip() |
|
|
|
|
|
@staticmethod |
|
|
def call_gemini(prompt, api_key): |
|
|
response = requests.post( |
|
|
f"https://generativelanguage.googleapis.com/v1beta/models/gemini-1.5-pro:generateContent?key={api_key}", |
|
|
json={"contents": [{"parts": [{"text": prompt}]}]}, |
|
|
headers={"Content-Type": "application/json"} |
|
|
) |
|
|
return BlogGenerator.clean_output(response.json()["candidates"][0]["content"]["parts"][0]["text"]) |
|
|
|
|
|
@staticmethod |
|
|
def generate_meta(keyword, transcript, api_key): |
|
|
prompt = f""" |
|
|
Create an SEO-friendly meta title (max 60 chars) and meta description (max 160 chars) for a blog about {keyword}. |
|
|
Use this content as reference: {transcript} |
|
|
Format: |
|
|
Title: ... |
|
|
Description: ... |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
@staticmethod |
|
|
def generate_slug_tags(keyword, api_key): |
|
|
prompt = f""" |
|
|
Suggest a URL-friendly slug and 3-5 relevant blog tags for the topic: {keyword}. |
|
|
Format: |
|
|
Slug: ... |
|
|
Tags: tag1, tag2, tag3... |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
@staticmethod |
|
|
def generate_schema(keyword, api_key): |
|
|
prompt = f""" |
|
|
Create JSON-LD structured data for an article about {keyword}, including FAQPage and HowTo if applicable. |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
@staticmethod |
|
|
def generate_faq(keyword, api_key): |
|
|
prompt = f""" |
|
|
Create 3-5 beginner-friendly FAQ questions and answers about {keyword}. |
|
|
Requirements: |
|
|
- Use question format "Q: [question]" |
|
|
- Answer in 2-3 simple sentences |
|
|
- Include the keyword naturally |
|
|
- Format as HTML with <div class='faq-item'> |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
@staticmethod |
|
|
def generate_step_by_step(keyword, api_key): |
|
|
prompt = f""" |
|
|
Create a simple step-by-step guide about {keyword} for beginners. |
|
|
Format: |
|
|
<h2>{keyword}: A Simple Step-by-Step Guide</h2> |
|
|
<ul><li>Item 1</li><li>Item 2</li></ul> |
|
|
<ol><li><strong>Step 1:</strong> Start by...</li></ol> |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
@staticmethod |
|
|
def generate_blog(transcript, keyword, pov, tone, length, internal_links, extra_keywords, api_key): |
|
|
word_count = { |
|
|
"Short": "800", |
|
|
"Standard": "1500-1700", |
|
|
"Long": "2000+" |
|
|
}[length] |
|
|
|
|
|
links_formatted = "" |
|
|
if internal_links: |
|
|
links = internal_links.split("\n") |
|
|
links_formatted = "\n".join([f"- <a href='{link.strip()}'>{link.strip()}</a>" for link in links if link.strip()]) |
|
|
|
|
|
extra_keywords_list = "" |
|
|
if extra_keywords: |
|
|
keywords = extra_keywords.split("\n") |
|
|
extra_keywords_list = ", ".join([kw.strip() for kw in keywords if kw.strip()]) |
|
|
|
|
|
prompt = f""" |
|
|
Create an SEO-optimized beginner-friendly blog post about: {keyword} |
|
|
Transcript: {transcript} |
|
|
|
|
|
Requirements: |
|
|
- POV: {pov}, Tone: {tone} |
|
|
- Word Count: {word_count} words |
|
|
- Structure: |
|
|
- Engaging title with keyword |
|
|
- First sentence as SEO meta description (max 160 chars) |
|
|
- Short intro (~100 words) |
|
|
- 3-5 H2 sections with bullet points and practical advice |
|
|
- Short paragraphs (2-3 sentences) |
|
|
- Keyword density ~1-2% |
|
|
- HTML format only with WordPress Gutenberg compatibility |
|
|
{f"- Naturally include these internal links: {links_formatted}" if links_formatted else ""} |
|
|
{f"- Sprinkle naturally these extra keywords: {extra_keywords_list}" if extra_keywords_list else ""} |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
|
|
|
@staticmethod |
|
|
def analyze_seo_score(content, keyword, api_key): |
|
|
prompt = f""" |
|
|
Analyze this blog content for SEO quality and provide a score from 0-100: |
|
|
Keyword: {keyword} |
|
|
Content: {content} |
|
|
|
|
|
Provide a breakdown with these components: |
|
|
- Keyword density score (0-20) |
|
|
- Readability score (0-20) |
|
|
- Structure score (0-20) |
|
|
- Meta data score (0-20) |
|
|
- Internal linking score (0-20) |
|
|
|
|
|
Format: |
|
|
Overall Score: XX/100 |
|
|
Keyword Density: XX/20 (explanation) |
|
|
Readability: XX/20 (explanation) |
|
|
Structure: XX/20 (explanation) |
|
|
Meta Data: XX/20 (explanation) |
|
|
Internal Linking: XX/20 (explanation) |
|
|
|
|
|
Top 3 Improvement Suggestions: |
|
|
1. ... |
|
|
2. ... |
|
|
3. ... |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
|
|
|
@staticmethod |
|
|
def generate_title_variations(keyword, transcript, api_key): |
|
|
prompt = f""" |
|
|
Generate 5 engaging and SEO-friendly title variations for a blog post about "{keyword}". |
|
|
Use this content as reference: {transcript[:500]} |
|
|
|
|
|
Requirements: |
|
|
- Include the keyword naturally |
|
|
- Keep each title under 60 characters |
|
|
- Use a mix of question, how-to, and list-based titles |
|
|
- Add emotional triggers where appropriate |
|
|
- Ensure WordPress compatibility |
|
|
|
|
|
Format: |
|
|
1. [Title 1] |
|
|
2. [Title 2] |
|
|
3. [Title 3] |
|
|
4. [Title 4] |
|
|
5. [Title 5] |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
|
|
|
@staticmethod |
|
|
def analyze_readability(content, api_key): |
|
|
prompt = f""" |
|
|
Analyze the readability of this blog content: |
|
|
{content[:2000]}... |
|
|
|
|
|
Provide: |
|
|
1. Estimated Flesch-Kincaid reading level |
|
|
2. Average words per sentence |
|
|
3. Percentage of complex words |
|
|
4. Passive voice percentage |
|
|
5. Overall readability score (0-100) |
|
|
|
|
|
Specific suggestions to improve: |
|
|
- 3 sentences that could be simplified |
|
|
- Words that could be replaced with simpler alternatives |
|
|
- Structure improvements for WordPress readability |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
|
|
|
@staticmethod |
|
|
def generate_social_snippets(content, keyword, api_key): |
|
|
prompt = f""" |
|
|
Create social media post snippets promoting a blog about "{keyword}" for: |
|
|
|
|
|
1. Twitter/X (max 280 chars, include hashtags) |
|
|
2. Facebook (100-250 words with call to action) |
|
|
3. LinkedIn (professional tone, 150-250 words) |
|
|
4. Instagram (caption with relevant hashtags) |
|
|
5. Pinterest (short description with SEO keywords) |
|
|
|
|
|
Reference content: |
|
|
{content[:1000]}... |
|
|
|
|
|
Format each snippet ready for copy-paste into WordPress social sharing plugins. |
|
|
Include emojis where appropriate. |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
|
|
|
@staticmethod |
|
|
def generate_citations(keyword, api_key): |
|
|
prompt = f""" |
|
|
Generate 5 relevant citation sources for a blog about "{keyword}". |
|
|
|
|
|
For each source provide: |
|
|
1. Author name(s) |
|
|
2. Publication title |
|
|
3. Publication date (within last 2 years) |
|
|
4. URL |
|
|
5. Brief description of why this source is valuable |
|
|
6. A formatted citation in APA style |
|
|
|
|
|
Focus on authoritative sources like: |
|
|
- Peer-reviewed journals |
|
|
- Government publications |
|
|
- Industry reports |
|
|
- Expert blogs with high domain authority |
|
|
|
|
|
Format in HTML ready for WordPress insertion. |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
|
|
|
@staticmethod |
|
|
def check_uniqueness(content, api_key): |
|
|
prompt = f""" |
|
|
Analyze this content for potential plagiarism or duplicate content issues: |
|
|
{content[:3000]}... |
|
|
|
|
|
Provide: |
|
|
1. Uniqueness score (estimated percentage of original content) |
|
|
2. Highlight 3-5 phrases that might be common or potentially duplicative |
|
|
3. Suggestions to make the content more unique |
|
|
4. WordPress-specific recommendations for avoiding duplicate content penalties |
|
|
|
|
|
Note: This is an AI-based estimation and not a replacement for professional plagiarism detection tools. |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
|
|
|
@staticmethod |
|
|
def format_for_wordpress(content, keyword, api_key): |
|
|
prompt = f""" |
|
|
Optimize this HTML content for WordPress: |
|
|
{content} |
|
|
|
|
|
Make these WordPress-specific adjustments: |
|
|
1. Format headings with proper Gutenberg compatibility |
|
|
2. Add <!-- wp:paragraph --> tags where appropriate |
|
|
3. Optimize image placeholders with WordPress figure blocks |
|
|
4. Format lists for proper WordPress display |
|
|
5. Add Yoast SEO compatible meta tags |
|
|
6. Ensure responsive design elements |
|
|
7. Add jump links for table of contents |
|
|
|
|
|
Keep the keyword "{keyword}" optimized throughout. |
|
|
""" |
|
|
return BlogGenerator.call_gemini(prompt, api_key) |
|
|
|
|
|
def process_input(transcript, keyword, pov, tone, length, internal_links, extra_keywords, api_key, |
|
|
enable_wp_format, enable_title_variations, enable_seo_score, enable_readability, |
|
|
enable_social_snippets, enable_citations, enable_uniqueness): |
|
|
if not api_key: |
|
|
return "β οΈ Please enter your Gemini API key", "", None |
|
|
|
|
|
results = {} |
|
|
|
|
|
|
|
|
main_blog = BlogGenerator.generate_blog(transcript, keyword, pov, tone, length, internal_links, extra_keywords, api_key) |
|
|
results["main_blog"] = main_blog |
|
|
|
|
|
|
|
|
results["faq_section"] = BlogGenerator.generate_faq(keyword, api_key) |
|
|
results["steps_section"] = BlogGenerator.generate_step_by_step(keyword, api_key) |
|
|
results["meta_data"] = BlogGenerator.generate_meta(keyword, transcript, api_key) |
|
|
results["slug_tags"] = BlogGenerator.generate_slug_tags(keyword, api_key) |
|
|
|
|
|
|
|
|
if enable_wp_format: |
|
|
results["wp_formatted"] = BlogGenerator.format_for_wordpress(main_blog, keyword, api_key) |
|
|
|
|
|
if enable_title_variations: |
|
|
results["title_variations"] = BlogGenerator.generate_title_variations(keyword, transcript, api_key) |
|
|
|
|
|
if enable_seo_score: |
|
|
results["seo_score"] = BlogGenerator.analyze_seo_score(main_blog, keyword, api_key) |
|
|
|
|
|
if enable_readability: |
|
|
results["readability"] = BlogGenerator.analyze_readability(main_blog, api_key) |
|
|
|
|
|
if enable_social_snippets: |
|
|
results["social_snippets"] = BlogGenerator.generate_social_snippets(main_blog, keyword, api_key) |
|
|
|
|
|
if enable_citations: |
|
|
results["citations"] = BlogGenerator.generate_citations(keyword, api_key) |
|
|
|
|
|
if enable_uniqueness: |
|
|
results["uniqueness"] = BlogGenerator.check_uniqueness(main_blog, api_key) |
|
|
|
|
|
|
|
|
final_output = f""" |
|
|
{results.get('wp_formatted', results['main_blog'])} |
|
|
|
|
|
{results['steps_section']} |
|
|
<h2>Common Questions About {keyword}</h2> |
|
|
{results['faq_section']} |
|
|
<hr> |
|
|
<h2>π SEO Metadata</h2> |
|
|
<pre>{results['meta_data']}</pre> |
|
|
<h2>π URL Slug & Tags</h2> |
|
|
<pre>{results['slug_tags']}</pre> |
|
|
""" |
|
|
|
|
|
|
|
|
if enable_title_variations: |
|
|
final_output += f""" |
|
|
<h2>π Title Variations</h2> |
|
|
<pre>{results['title_variations']}</pre> |
|
|
""" |
|
|
|
|
|
if enable_seo_score: |
|
|
final_output += f""" |
|
|
<h2>π SEO Score Analysis</h2> |
|
|
<pre>{results['seo_score']}</pre> |
|
|
""" |
|
|
|
|
|
if enable_readability: |
|
|
final_output += f""" |
|
|
<h2>π Readability Analysis</h2> |
|
|
<pre>{results['readability']}</pre> |
|
|
""" |
|
|
|
|
|
if enable_social_snippets: |
|
|
final_output += f""" |
|
|
<h2>π± Social Media Snippets</h2> |
|
|
<div class="social-snippets"> |
|
|
{results['social_snippets']} |
|
|
</div> |
|
|
""" |
|
|
|
|
|
if enable_citations: |
|
|
final_output += f""" |
|
|
<h2>π Citations & References</h2> |
|
|
<div class="citations"> |
|
|
{results['citations']} |
|
|
</div> |
|
|
""" |
|
|
|
|
|
if enable_uniqueness: |
|
|
final_output += f""" |
|
|
<h2>π Content Uniqueness Analysis</h2> |
|
|
<pre>{results['uniqueness']}</pre> |
|
|
""" |
|
|
|
|
|
|
|
|
filename = f"{keyword.replace(' ', '_')}_{datetime.now().strftime('%Y%m%d%H%M%S')}.html" |
|
|
filepath = os.path.join("/tmp", filename) |
|
|
with open(filepath, "w", encoding="utf-8") as f: |
|
|
f.write(final_output) |
|
|
|
|
|
return final_output, markdown2.markdown(final_output), filepath |
|
|
|
|
|
|
|
|
with gr.Blocks(theme=gr.themes.Soft(), title="Enhanced SEO Blog Generator for WordPress") as app: |
|
|
gr.Markdown(""" |
|
|
# π Enhanced SEO Blog Generator for WordPress |
|
|
Generate SEO-optimized content with advanced features including WordPress compatibility! |
|
|
""") |
|
|
|
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
api_key = gr.Textbox(label="Gemini API Key", type="password", placeholder="Enter your API key") |
|
|
keyword = gr.Textbox(label="Primary Keyword", placeholder="e.g., 'sourdough bread'") |
|
|
pov = gr.Radio(label="Point of View", choices=["First Person", "Second Person", "Third Person"], value="Second Person") |
|
|
tone = gr.Dropdown( |
|
|
label="Blog Tone", |
|
|
choices=["Neutral", "Engaging", "Professional", "Informative", "News", "Promotional", "Conversational", "Storytelling", "Educational", "How-to", "Review", "Humorous", "Casual", "Inspirational"], |
|
|
value="Engaging" |
|
|
) |
|
|
length = gr.Radio(label="Content Length", choices=["Short", "Standard", "Long"], value="Standard") |
|
|
transcript = gr.Textbox(label="Transcript/Notes", lines=6, placeholder="Paste your reference content...") |
|
|
internal_links = gr.Textbox(label="Internal Links (one URL per line)", lines=4, placeholder="https://yourblog.com/article1\nhttps://yourblog.com/article2") |
|
|
extra_keywords = gr.Textbox(label="Extra Keywords (one per line)", lines=4, placeholder="kefir health benefits\nhomemade kefir tips") |
|
|
|
|
|
gr.Markdown("### π Advanced Features") |
|
|
with gr.Row(): |
|
|
with gr.Column(): |
|
|
enable_wp_format = gr.Checkbox(label="WordPress Formatting", value=True) |
|
|
enable_title_variations = gr.Checkbox(label="Title Variations", value=True) |
|
|
enable_seo_score = gr.Checkbox(label="SEO Score Analysis", value=True) |
|
|
enable_readability = gr.Checkbox(label="Readability Analysis", value=True) |
|
|
with gr.Column(): |
|
|
enable_social_snippets = gr.Checkbox(label="Social Media Snippets", value=True) |
|
|
enable_citations = gr.Checkbox(label="Citations & References", value=True) |
|
|
enable_uniqueness = gr.Checkbox(label="Content Uniqueness Check", value=True) |
|
|
|
|
|
btn = gr.Button("Generate WordPress-Ready Blog", variant="primary") |
|
|
|
|
|
with gr.Column(): |
|
|
tabs = gr.Tabs() |
|
|
with tabs: |
|
|
with gr.TabItem("Preview"): |
|
|
html_output = gr.HTML(label="Full SEO Article Preview") |
|
|
with gr.TabItem("Markdown"): |
|
|
md_output = gr.Code(label="Markdown Version", language="markdown") |
|
|
with gr.TabItem("Download"): |
|
|
file_output = gr.File(label="β¬οΈ Download HTML File") |
|
|
gr.Markdown(""" |
|
|
### WordPress Import Instructions |
|
|
1. Download the HTML file |
|
|
2. In WordPress, create a new post |
|
|
3. Click the three dots in the top-right and select "Code Editor" |
|
|
4. Paste the HTML content |
|
|
5. Switch back to "Visual Editor" to make any final adjustments |
|
|
6. Update your meta data using Yoast or other SEO plugins |
|
|
""") |
|
|
|
|
|
btn.click( |
|
|
fn=process_input, |
|
|
inputs=[ |
|
|
transcript, keyword, pov, tone, length, internal_links, extra_keywords, api_key, |
|
|
enable_wp_format, enable_title_variations, enable_seo_score, enable_readability, |
|
|
enable_social_snippets, enable_citations, enable_uniqueness |
|
|
], |
|
|
outputs=[html_output, md_output, file_output] |
|
|
) |
|
|
|
|
|
app.launch(share=True) |