Spaces:
Sleeping
Sleeping
| # -*- coding: utf-8 -*- | |
| """ | |
| 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 | |
| """ | |
| #pip install -r requirements.txt | |
| import gradio as gr | |
| import requests | |
| import markdown2 | |
| import os | |
| import re | |
| from datetime import datetime | |
| class BlogGenerator: | |
| def clean_output(content): | |
| return re.sub(r'```html|```', '', content).strip() | |
| 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"]) | |
| def inject_emotional_tone(content, keyword, tone, api_key): | |
| prompt = f""" | |
| Enhance the following blog content with contextual emotional tones to make it more engaging for readers: | |
| - Ensure the emotional tone aligns with the {tone} of the blog. | |
| - Use emotionally charged language where appropriate to create empathy, excitement, or curiosity. | |
| - Keep the content natural and easy to read. | |
| Content: {content} | |
| """ | |
| return BlogGenerator.call_gemini(prompt, api_key) | |
| 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) | |
| 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) | |
| 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) | |
| 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) | |
| 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) | |
| 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) | |
| def generate_image_alt_text(content, api_key): | |
| prompt = f""" | |
| Analyze the following blog content and suggest alt text for any images. The alt text should be descriptive, relevant to the content, and SEO-optimized. | |
| Content: {content} | |
| """ | |
| return BlogGenerator.call_gemini(prompt, api_key) | |
| # New Feature: Content Optimization Score | |
| 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) | |
| # New Feature: Title Variations | |
| 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) | |
| # New Feature: Readability Analysis | |
| 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) | |
| # New Feature: Social Media Snippets | |
| 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) | |
| # New Feature: Citation Generator | |
| 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) | |
| # New Feature: Content Uniqueness Check | |
| 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) | |
| # New Feature: WordPress Optimization # #5. Add Yoast SEO compatible meta tags 2. Add <!-- wp:paragraph --> tags where appropriate 6. Add jump links for table of contents | |
| 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. Optimize image placeholders with WordPress figure blocks | |
| 3. Format lists for proper WordPress display | |
| 4. Ensure responsive design elements | |
| 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, enable_emotional_tone): | |
| if not api_key: | |
| return "β οΈ Please enter your Gemini API key", "", None | |
| results = {} | |
| # Generate main blog content | |
| main_blog = BlogGenerator.generate_blog(transcript, keyword, pov, tone, length, internal_links, extra_keywords, api_key) | |
| # Inject emotional tone if enabled | |
| if enable_emotional_tone: | |
| main_blog = BlogGenerator.inject_emotional_tone(main_blog, keyword, tone, api_key) | |
| results["main_blog"] = main_blog | |
| # Generate standard components | |
| 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) | |
| # Generate optional components based on user selection | |
| 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) | |
| # Generate image alt text suggestions | |
| image_alt_text = BlogGenerator.generate_image_alt_text(main_blog, api_key) | |
| results["image_alt_text"] = image_alt_text | |
| # Compile the final output | |
| 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> | |
| """ | |
| # Add optional components to output | |
| 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> | |
| """ | |
| final_output += f""" | |
| <h2>πΌοΈ Image Alt Text Suggestions</h2> | |
| <pre>{results['image_alt_text']}</pre> | |
| """ | |
| # Generate file | |
| 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 | |
| # UI Implementation with new features | |
| 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) | |
| enable_emotional_tone = gr.Checkbox(label="Emotional Tone Injection", 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, enable_emotional_tone | |
| ], | |
| outputs=[html_output, md_output, file_output] | |
| ) | |
| app.launch(share=True) | |