Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
|
@@ -1,14 +1,564 @@
|
|
| 1 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2 |
import google.generativeai as genai
|
| 3 |
import os
|
| 4 |
from dotenv import load_dotenv
|
| 5 |
import time
|
|
|
|
|
|
|
|
|
|
|
|
|
| 6 |
|
| 7 |
# Load environment variables from .env file if it exists
|
| 8 |
load_dotenv()
|
| 9 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
# Function to generate SEO plan with proper error handling
|
| 11 |
-
def generate_seo_plan(topic, api_key, temperature=0.7, max_tokens=4000):
|
| 12 |
# Input validation
|
| 13 |
if not topic.strip():
|
| 14 |
return "⚠️ Please enter a fermentation topic to generate an SEO plan."
|
|
@@ -34,10 +584,10 @@ def generate_seo_plan(topic, api_key, temperature=0.7, max_tokens=4000):
|
|
| 34 |
)
|
| 35 |
|
| 36 |
# Update status
|
| 37 |
-
yield "🧠 Building SEO prompt for your
|
| 38 |
|
| 39 |
-
# Build the prompt
|
| 40 |
-
prompt = build_prompt(topic)
|
| 41 |
|
| 42 |
# Update status
|
| 43 |
yield "🚀 Generating SEO plan with Gemini 1.5 Pro..."
|
|
@@ -62,50 +612,9 @@ def generate_seo_plan(topic, api_key, temperature=0.7, max_tokens=4000):
|
|
| 62 |
else:
|
| 63 |
yield f"⚠️ Error: {error_message}"
|
| 64 |
|
| 65 |
-
#
|
| 66 |
-
def
|
| 67 |
-
return
|
| 68 |
-
Act as an elite-level SEO strategist and content creator with deep expertise in food blogs, particularly fermentation. I run a blog about fermentation, and my primary goal is to increase organic traffic, educate beginners, and establish thought leadership. My target audience is beginners curious about home fermentation and health-conscious individuals.
|
| 69 |
-
|
| 70 |
-
For the specific topic: '{topic}'
|
| 71 |
-
|
| 72 |
-
Analyze and generate a comprehensive SEO content plan designed to rank highly on Google and provide exceptional user value. Ensure all outputs adhere to E-E-A-T principles.
|
| 73 |
-
|
| 74 |
-
I require the following, formatted in clean markdown:
|
| 75 |
-
|
| 76 |
-
1. **Strategic Keyword Analysis:**
|
| 77 |
-
* **Primary Target Keyword:**
|
| 78 |
-
* **Secondary Keywords:** 2-3 closely related, high-intent keywords.
|
| 79 |
-
* **Long-Tail Keywords & User Questions:** 5-7 specific user-searched phrases.
|
| 80 |
-
* **Semantic/LSI Keywords:** 5-7 contextually related terms.
|
| 81 |
-
* **Search Intent Analysis:** (Informational, Commercial, etc.)
|
| 82 |
-
|
| 83 |
-
2. **Competitive Landscape Overview (Top 3-5 Competitors):**
|
| 84 |
-
* For each:
|
| 85 |
-
* URL
|
| 86 |
-
* Strengths
|
| 87 |
-
* Weaknesses
|
| 88 |
-
* Content angle/hook
|
| 89 |
-
|
| 90 |
-
3. **Content Gaps & Unique Value Proposition:**
|
| 91 |
-
* Missing topics or angles
|
| 92 |
-
* Unique insights or differentiators for *my* blog
|
| 93 |
-
|
| 94 |
-
4. **Optimized Blog Post Outline:**
|
| 95 |
-
* **H1 Title:**
|
| 96 |
-
* **Meta Description:** (under 160 characters)
|
| 97 |
-
* **Full H2/H3 outline:**
|
| 98 |
-
* **Suggested Visuals:** Where applicable
|
| 99 |
-
|
| 100 |
-
5. **User-Focused FAQ Section:** 3–5 related to '{topic}'
|
| 101 |
-
|
| 102 |
-
6. **Internal & External Linking Plan:**
|
| 103 |
-
* **Internal:** 2-3 relevant articles with anchor suggestions
|
| 104 |
-
* **External:** 1-2 reputable sources (.edu, .org, studies)
|
| 105 |
-
|
| 106 |
-
7. **E-E-A-T Enhancements:**
|
| 107 |
-
* 1-2 ways to show experience, trust, and authority in the content
|
| 108 |
-
"""
|
| 109 |
|
| 110 |
# Save API key to user's preferences
|
| 111 |
def save_api_key(api_key):
|
|
@@ -115,10 +624,6 @@ def save_api_key(api_key):
|
|
| 115 |
return "✅ API key saved successfully!"
|
| 116 |
return "⚠️ Please enter an API key to save"
|
| 117 |
|
| 118 |
-
# Function to clear outputs
|
| 119 |
-
def clear_outputs():
|
| 120 |
-
return "", gr.update(value="")
|
| 121 |
-
|
| 122 |
# Define theme for better visual experience
|
| 123 |
custom_theme = gr.themes.Soft(
|
| 124 |
primary_hue="green",
|
|
@@ -141,14 +646,14 @@ with gr.Blocks(title="Fermentation SEO Assistant", theme=custom_theme, css="""
|
|
| 141 |
overflow-y: auto;
|
| 142 |
border-left: 4px solid #84cc16;
|
| 143 |
padding-left: 15px;
|
| 144 |
-
|
| 145 |
border-radius: 6px;
|
| 146 |
transition: all 0.3s ease;
|
| 147 |
}
|
| 148 |
|
| 149 |
#seo-output-container:empty {
|
| 150 |
border-left-color: #e5e7eb;
|
| 151 |
-
|
| 152 |
}
|
| 153 |
|
| 154 |
.loading-spinner {
|
|
|
|
| 1 |
+
# Main Gradio app
|
| 2 |
+
with gr.Blocks(title="Fermentation SEO Assistant", theme=custom_theme, css="""
|
| 3 |
+
#seo-output-container {
|
| 4 |
+
min-height: 300px;
|
| 5 |
+
max-height: 800px;
|
| 6 |
+
overflow-y: auto;
|
| 7 |
+
border-left: 4px solid #84cc16;
|
| 8 |
+
padding-left: 15px;
|
| 9 |
+
background-color: #f8fafc;
|
| 10 |
+
border-radius: 6px;
|
| 11 |
+
transition: all 0.3s ease;
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
#seo-output-container:empty {
|
| 15 |
+
border-left-color: #e5e7eb;
|
| 16 |
+
background-color: #ffffff;
|
| 17 |
+
}
|
| 18 |
+
|
| 19 |
+
.loading-spinner {
|
| 20 |
+
display: inline-block;
|
| 21 |
+
width: 50px;
|
| 22 |
+
height: 50px;
|
| 23 |
+
border: 3px solid rgba(0,0,0,.3);
|
| 24 |
+
border-radius: 50%;
|
| 25 |
+
border-top-color: #84cc16;
|
| 26 |
+
animation: spin 1s ease-in-out infinite;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
@keyframes spin {
|
| 30 |
+
to { transform: rotate(360deg); }
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
.tab-selected {
|
| 34 |
+
border-bottom: 3px solid #84cc16 !important;
|
| 35 |
+
font-weight: bold;
|
| 36 |
+
}
|
| 37 |
+
""") as app:
|
| 38 |
+
# Header
|
| 39 |
+
gr.Markdown("""
|
| 40 |
+
# 🌱 Advanced Food Blog SEO Content Planner
|
| 41 |
+
|
| 42 |
+
Generate comprehensive SEO plans for your food blog posts using Google's Gemini 1.5 Pro.
|
| 43 |
+
""")
|
| 44 |
+
|
| 45 |
+
# Create tabs for different sections
|
| 46 |
+
with gr.Tabs() as tabs:
|
| 47 |
+
# Main Generator Tab
|
| 48 |
+
with gr.TabItem("SEO Generator", id="generator_tab"):
|
| 49 |
+
# API Key & Configuration Section
|
| 50 |
+
with gr.Accordion("API Key & Settings", open=False):
|
| 51 |
+
with gr.Row():
|
| 52 |
+
api_key_input = gr.Textbox(
|
| 53 |
+
label="Gemini API Key",
|
| 54 |
+
placeholder="Enter your Google Gemini API key",
|
| 55 |
+
value=os.getenv("GEMINI_API_KEY", ""),
|
| 56 |
+
type="password"
|
| 57 |
+
)
|
| 58 |
+
save_btn = gr.Button("💾 Save Key")
|
| 59 |
+
|
| 60 |
+
with gr.Row():
|
| 61 |
+
temperature = gr.Slider(
|
| 62 |
+
minimum=0.0,
|
| 63 |
+
maximum=1.0,
|
| 64 |
+
value=0.7,
|
| 65 |
+
step=0.1,
|
| 66 |
+
label="Temperature (Creativity)",
|
| 67 |
+
info="Higher values = more creative, Lower values = more focused"
|
| 68 |
+
)
|
| 69 |
+
max_tokens = gr.Slider(
|
| 70 |
+
minimum=1000,
|
| 71 |
+
maximum=8000,
|
| 72 |
+
value=4000,
|
| 73 |
+
step=500,
|
| 74 |
+
label="Max Output Length",
|
| 75 |
+
info="Maximum number of tokens in the response"
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
save_btn.click(fn=save_api_key, inputs=api_key_input, outputs=gr.Textbox(label="Status"))
|
| 79 |
+
|
| 80 |
+
# Main content
|
| 81 |
+
with gr.Row():
|
| 82 |
+
with gr.Column(scale=1):
|
| 83 |
+
# Input section
|
| 84 |
+
topic_input = gr.Textbox(
|
| 85 |
+
label="🌶️ Your Food Topic",
|
| 86 |
+
placeholder="e.g., How to Make Kimchi at Home",
|
| 87 |
+
lines=2
|
| 88 |
+
)
|
| 89 |
+
|
| 90 |
+
# Template and language selectors
|
| 91 |
+
template_dropdown = gr.Dropdown(
|
| 92 |
+
choices=list(TEMPLATES.keys()),
|
| 93 |
+
value="fermentation",
|
| 94 |
+
label="Content Template",
|
| 95 |
+
info="Choose a specialized template for your food niche"
|
| 96 |
+
)
|
| 97 |
+
|
| 98 |
+
language_dropdown = gr.Dropdown(
|
| 99 |
+
choices=list(LANGUAGES.keys()),
|
| 100 |
+
value="English",
|
| 101 |
+
label="Target Language",
|
| 102 |
+
info="Optimize keywords for a specific language"
|
| 103 |
+
)
|
| 104 |
+
|
| 105 |
+
with gr.Row():
|
| 106 |
+
generate_btn = gr.Button("✨ Generate SEO Plan", variant="primary")
|
| 107 |
+
clear_btn = gr.Button("🔄 Clear", variant="secondary")
|
| 108 |
+
|
| 109 |
+
# Example topics for quick selection
|
| 110 |
+
gr.Examples(
|
| 111 |
+
examples=[
|
| 112 |
+
"Beginner's Guide to Fermenting Vegetables",
|
| 113 |
+
"How to Make Kombucha at Home",
|
| 114 |
+
"The Health Benefits of Fermented Foods",
|
| 115 |
+
"Wild Fermentation: Using Natural Yeasts and Bacteria",
|
| 116 |
+
"Troubleshooting Common Fermentation Problems"
|
| 117 |
+
],
|
| 118 |
+
inputs=topic_input,
|
| 119 |
+
label="Example Topics"
|
| 120 |
+
)
|
| 121 |
+
|
| 122 |
+
with gr.Column(scale=2):
|
| 123 |
+
# Output section with a visually appealing container
|
| 124 |
+
with gr.Group():
|
| 125 |
+
output_header = gr.Markdown("### Your SEO Plan Will Appear Here")
|
| 126 |
+
# Add progress indicator
|
| 127 |
+
progress_bar = gr.Progress(track_tqdm=True)
|
| 128 |
+
seo_output = gr.Markdown(elem_id="seo-output-container")
|
| 129 |
+
|
| 130 |
+
# Export button
|
| 131 |
+
with gr.Row():
|
| 132 |
+
export_html_btn = gr.Button("📄 Export as HTML", variant="secondary")
|
| 133 |
+
export_status = gr.Textbox(label="Export Status", interactive=False)
|
| 134 |
+
|
| 135 |
+
# Button actions for main tab
|
| 136 |
+
generate_btn.click(
|
| 137 |
+
fn=generate_seo_plan,
|
| 138 |
+
inputs=[topic_input, api_key_input, template_dropdown, language_dropdown, temperature, max_tokens],
|
| 139 |
+
outputs=seo_output,
|
| 140 |
+
api_name="generate",
|
| 141 |
+
show_progress="full"
|
| 142 |
+
)
|
| 143 |
+
|
| 144 |
+
clear_btn.click(
|
| 145 |
+
fn=clear_outputs,
|
| 146 |
+
inputs=None,
|
| 147 |
+
outputs=[topic_input, seo_output]
|
| 148 |
+
)
|
| 149 |
+
|
| 150 |
+
export_html_btn.click(
|
| 151 |
+
fn=export_html,
|
| 152 |
+
inputs=[seo_output, topic_input],
|
| 153 |
+
outputs=export_status
|
| 154 |
+
)
|
| 155 |
+
|
| 156 |
+
# Template Manager Tab
|
| 157 |
+
with gr.TabItem("Template Manager", id="template_tab"):
|
| 158 |
+
gr.Markdown("## Create and Manage Content Templates")
|
| 159 |
+
|
| 160 |
+
with gr.Row():
|
| 161 |
+
with gr.Column(scale=1):
|
| 162 |
+
template_name_input = gr.Textbox(
|
| 163 |
+
label="Template Name",
|
| 164 |
+
placeholder="e.g., baking, vegan, desserts",
|
| 165 |
+
lines=1
|
| 166 |
+
)
|
| 167 |
+
|
| 168 |
+
template_selector = gr.Dropdown(
|
| 169 |
+
choices=list(TEMPLATES.keys()),
|
| 170 |
+
label="Load Existing Template",
|
| 171 |
+
info="Select a template to view or edit"
|
| 172 |
+
)
|
| 173 |
+
|
| 174 |
+
with gr.Column(scale=2):
|
| 175 |
+
template_content = gr.Textbox(
|
| 176 |
+
labelimport gradio as gr
|
| 177 |
import google.generativeai as genai
|
| 178 |
import os
|
| 179 |
from dotenv import load_dotenv
|
| 180 |
import time
|
| 181 |
+
import json
|
| 182 |
+
import markdown
|
| 183 |
+
import base64
|
| 184 |
+
from datetime import datetime
|
| 185 |
|
| 186 |
# Load environment variables from .env file if it exists
|
| 187 |
load_dotenv()
|
| 188 |
|
| 189 |
+
# Default templates
|
| 190 |
+
DEFAULT_TEMPLATES = {
|
| 191 |
+
"fermentation": """
|
| 192 |
+
Act as an elite-level SEO strategist and content creator with deep expertise in food blogs, particularly fermentation. I run a blog about fermentation, and my primary goal is to increase organic traffic, educate beginners, and establish thought leadership. My target audience is beginners curious about home fermentation and health-conscious individuals.
|
| 193 |
+
|
| 194 |
+
For the specific topic: '{topic}'
|
| 195 |
+
|
| 196 |
+
Analyze and generate a comprehensive SEO content plan designed to rank highly on Google and provide exceptional user value. Ensure all outputs adhere to E-E-A-T principles.
|
| 197 |
+
|
| 198 |
+
I require the following, formatted in clean markdown:
|
| 199 |
+
|
| 200 |
+
1. **Strategic Keyword Analysis:**
|
| 201 |
+
* **Primary Target Keyword:**
|
| 202 |
+
* **Secondary Keywords:** 2-3 closely related, high-intent keywords.
|
| 203 |
+
* **Long-Tail Keywords & User Questions:** 5-7 specific user-searched phrases.
|
| 204 |
+
* **Semantic/LSI Keywords:** 5-7 contextually related terms.
|
| 205 |
+
* **Search Intent Analysis:** (Informational, Commercial, etc.)
|
| 206 |
+
|
| 207 |
+
2. **Competitive Landscape Overview (Top 3-5 Competitors):**
|
| 208 |
+
* For each:
|
| 209 |
+
* URL
|
| 210 |
+
* Strengths
|
| 211 |
+
* Weaknesses
|
| 212 |
+
* Content angle/hook
|
| 213 |
+
|
| 214 |
+
3. **Content Gaps & Unique Value Proposition:**
|
| 215 |
+
* Missing topics or angles
|
| 216 |
+
* Unique insights or differentiators for *my* blog
|
| 217 |
+
|
| 218 |
+
4. **Optimized Blog Post Outline:**
|
| 219 |
+
* **H1 Title:**
|
| 220 |
+
* **Meta Description:** (under 160 characters)
|
| 221 |
+
* **Full H2/H3 outline:**
|
| 222 |
+
* **Suggested Visuals:** Where applicable
|
| 223 |
+
|
| 224 |
+
5. **User-Focused FAQ Section:** 3–5 related to '{topic}'
|
| 225 |
+
|
| 226 |
+
6. **Internal & External Linking Plan:**
|
| 227 |
+
* **Internal:** 2-3 relevant articles with anchor suggestions
|
| 228 |
+
* **External:** 1-2 reputable sources (.edu, .org, studies)
|
| 229 |
+
|
| 230 |
+
7. **E-E-A-T Enhancements:**
|
| 231 |
+
* 1-2 ways to show experience, trust, and authority in the content
|
| 232 |
+
""",
|
| 233 |
+
"baking": """
|
| 234 |
+
Act as an elite-level SEO strategist and content creator with deep expertise in food blogs, particularly baking and pastry. I run a blog about baking, and my primary goal is to increase organic traffic, help home bakers improve their skills, and showcase unique recipes. My target audience is home bakers of all skill levels looking for reliable recipes and techniques.
|
| 235 |
+
|
| 236 |
+
For the specific topic: '{topic}'
|
| 237 |
+
|
| 238 |
+
Analyze and generate a comprehensive SEO content plan designed to rank highly on Google and provide exceptional user value. Ensure all outputs adhere to E-E-A-T principles.
|
| 239 |
+
|
| 240 |
+
I require the following, formatted in clean markdown:
|
| 241 |
+
|
| 242 |
+
1. **Strategic Keyword Analysis:**
|
| 243 |
+
* **Primary Target Keyword:**
|
| 244 |
+
* **Secondary Keywords:** 2-3 closely related, high-intent keywords.
|
| 245 |
+
* **Long-Tail Keywords & User Questions:** 5-7 specific user-searched phrases.
|
| 246 |
+
* **Seasonal/Holiday Keywords:** 2-3 if applicable
|
| 247 |
+
* **Search Intent Analysis:** (Recipe-seeking, Technique-learning, Equipment-buying, etc.)
|
| 248 |
+
|
| 249 |
+
2. **Competitive Landscape Overview (Top 3-5 Competitors):**
|
| 250 |
+
* For each:
|
| 251 |
+
* URL
|
| 252 |
+
* Recipe uniqueness/approach
|
| 253 |
+
* Visual presentation
|
| 254 |
+
* User engagement factors
|
| 255 |
+
|
| 256 |
+
3. **Recipe Uniqueness & Value Proposition:**
|
| 257 |
+
* Distinctive ingredients or techniques
|
| 258 |
+
* How my recipe differs from competitors
|
| 259 |
+
* Troubleshooting common issues other recipes don't address
|
| 260 |
+
|
| 261 |
+
4. **Optimized Blog Post Outline:**
|
| 262 |
+
* **H1 Title:**
|
| 263 |
+
* **Meta Description:** (under 160 characters)
|
| 264 |
+
* **Full H2/H3 outline** (including "Why This Recipe Works", "Ingredients", "Step-by-Step Instructions", "Storage & Make-Ahead Tips")
|
| 265 |
+
* **Recipe Schema Markup Elements:**
|
| 266 |
+
* **Required Photo/Video Content:**
|
| 267 |
+
|
| 268 |
+
5. **User-Focused FAQ Section:** 3–5 related to '{topic}'
|
| 269 |
+
|
| 270 |
+
6. **Internal & External Linking Plan:**
|
| 271 |
+
* **Internal:** 2-3 relevant recipes with anchor suggestions
|
| 272 |
+
* **External:** 1-2 reputable sources for techniques or ingredient information
|
| 273 |
+
|
| 274 |
+
7. **E-E-A-T Enhancements:**
|
| 275 |
+
* Recipe testing notes to include
|
| 276 |
+
* Personal experience elements to highlight
|
| 277 |
+
* Scientific explanation opportunities
|
| 278 |
+
""",
|
| 279 |
+
"plant_based": """
|
| 280 |
+
Act as an elite-level SEO strategist and content creator with deep expertise in plant-based and vegan food blogs. I run a blog about plant-based cooking, and my primary goal is to increase organic traffic, help people transition to more plant-based eating, and provide delicious alternatives to animal products. My target audience includes vegans, vegetarians, flexitarians, and the plant-curious.
|
| 281 |
+
|
| 282 |
+
For the specific topic: '{topic}'
|
| 283 |
+
|
| 284 |
+
Analyze and generate a comprehensive SEO content plan designed to rank highly on Google and provide exceptional user value. Ensure all outputs adhere to E-E-A-T principles.
|
| 285 |
+
|
| 286 |
+
I require the following, formatted in clean markdown:
|
| 287 |
+
|
| 288 |
+
1. **Strategic Keyword Analysis:**
|
| 289 |
+
* **Primary Target Keyword:**
|
| 290 |
+
* **Secondary Keywords:** 2-3 closely related, high-intent keywords.
|
| 291 |
+
* **Long-Tail Keywords & User Questions:** 5-7 specific user-searched phrases.
|
| 292 |
+
* **Dietary Restriction Related Keywords:** (gluten-free, nut-free, soy-free, etc.)
|
| 293 |
+
* **Search Intent Analysis:** (Recipe-seeking, Nutrition information, Substitution help, etc.)
|
| 294 |
+
|
| 295 |
+
2. **Competitive Landscape Overview (Top 3-5 Competitors):**
|
| 296 |
+
* For each:
|
| 297 |
+
* URL
|
| 298 |
+
* Ingredient approach (whole foods vs. processed substitutes)
|
| 299 |
+
* Nutritional information provided
|
| 300 |
+
* User engagement factors
|
| 301 |
+
|
| 302 |
+
3. **Plant-Based Value Proposition:**
|
| 303 |
+
* Health/nutritional benefits to highlight
|
| 304 |
+
* Environmental/ethical angle if applicable
|
| 305 |
+
* Taste/texture comparisons to non-vegan alternatives
|
| 306 |
+
* Accessibility of ingredients
|
| 307 |
+
|
| 308 |
+
4. **Optimized Blog Post Outline:**
|
| 309 |
+
* **H1 Title:**
|
| 310 |
+
* **Meta Description:** (under 160 characters)
|
| 311 |
+
* **Full H2/H3 outline** (including "Why Choose Plant-Based", "Ingredients & Substitutions", "Step-by-Step Instructions", "Nutritional Information")
|
| 312 |
+
* **Recipe Schema Markup Elements:**
|
| 313 |
+
* **Required Photo Content:**
|
| 314 |
+
|
| 315 |
+
5. **User-Focused FAQ Section:** 3–5 related to '{topic}' (focusing on common substitution questions)
|
| 316 |
+
|
| 317 |
+
6. **Internal & External Linking Plan:**
|
| 318 |
+
* **Internal:** 2-3 relevant recipes with anchor suggestions
|
| 319 |
+
* **External:** 1-2 reputable sources for nutritional information
|
| 320 |
+
|
| 321 |
+
7. **E-E-A-T Enhancements:**
|
| 322 |
+
* Nutritional expertise to highlight
|
| 323 |
+
* Personal experience with plant-based eating
|
| 324 |
+
* Scientific/research citations to include
|
| 325 |
+
"""
|
| 326 |
+
}
|
| 327 |
+
|
| 328 |
+
# Default language settings
|
| 329 |
+
LANGUAGE_SETTINGS = {
|
| 330 |
+
"English": {
|
| 331 |
+
"search_engines": ["Google", "Bing", "DuckDuckGo"],
|
| 332 |
+
"localization_tips": "Focus on English-speaking markets (US, UK, Canada, Australia)",
|
| 333 |
+
"keyword_examples": ["recipe", "how to", "benefits of", "best", "easy", "homemade"]
|
| 334 |
+
},
|
| 335 |
+
"Spanish": {
|
| 336 |
+
"search_engines": ["Google", "Bing", "Yahoo"],
|
| 337 |
+
"localization_tips": "Target Spain and Latin American markets with regional variants",
|
| 338 |
+
"keyword_examples": ["receta", "cómo hacer", "beneficios de", "mejor", "fácil", "casero"]
|
| 339 |
+
},
|
| 340 |
+
"French": {
|
| 341 |
+
"search_engines": ["Google", "Qwant", "Bing"],
|
| 342 |
+
"localization_tips": "Focus on France, Belgium, Canada (Quebec), Switzerland",
|
| 343 |
+
"keyword_examples": ["recette", "comment faire", "avantages de", "meilleur", "facile", "fait maison"]
|
| 344 |
+
},
|
| 345 |
+
"German": {
|
| 346 |
+
"search_engines": ["Google", "Bing", "Yahoo"],
|
| 347 |
+
"localization_tips": "Target Germany, Austria, Switzerland with appropriate dialect considerations",
|
| 348 |
+
"keyword_examples": ["rezept", "wie man", "vorteile von", "beste", "einfach", "hausgemacht"]
|
| 349 |
+
}
|
| 350 |
+
}
|
| 351 |
+
|
| 352 |
+
# Function to save templates to file
|
| 353 |
+
def save_templates():
|
| 354 |
+
with open("templates.json", "w") as f:
|
| 355 |
+
json.dump(DEFAULT_TEMPLATES, f, indent=4)
|
| 356 |
+
|
| 357 |
+
with open("languages.json", "w") as f:
|
| 358 |
+
json.dump(LANGUAGE_SETTINGS, f, indent=4)
|
| 359 |
+
|
| 360 |
+
# Load templates if they exist, otherwise use defaults
|
| 361 |
+
def load_templates():
|
| 362 |
+
templates = DEFAULT_TEMPLATES.copy()
|
| 363 |
+
languages = LANGUAGE_SETTINGS.copy()
|
| 364 |
+
|
| 365 |
+
try:
|
| 366 |
+
if os.path.exists("templates.json"):
|
| 367 |
+
with open("templates.json", "r") as f:
|
| 368 |
+
templates = json.load(f)
|
| 369 |
+
except Exception as e:
|
| 370 |
+
print(f"Error loading templates: {e}")
|
| 371 |
+
|
| 372 |
+
try:
|
| 373 |
+
if os.path.exists("languages.json"):
|
| 374 |
+
with open("languages.json", "r") as f:
|
| 375 |
+
languages = json.load(f)
|
| 376 |
+
except Exception as e:
|
| 377 |
+
print(f"Error loading languages: {e}")
|
| 378 |
+
|
| 379 |
+
return templates, languages
|
| 380 |
+
|
| 381 |
+
# Initialize templates
|
| 382 |
+
TEMPLATES, LANGUAGES = load_templates()
|
| 383 |
+
|
| 384 |
+
# Generate HTML for export
|
| 385 |
+
def generate_html_export(content, title):
|
| 386 |
+
html_template = f"""<!DOCTYPE html>
|
| 387 |
+
<html lang="en">
|
| 388 |
+
<head>
|
| 389 |
+
<meta charset="UTF-8">
|
| 390 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 391 |
+
<title>{title} - SEO Plan</title>
|
| 392 |
+
<style>
|
| 393 |
+
body {{
|
| 394 |
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
| 395 |
+
line-height: 1.6;
|
| 396 |
+
color: #333;
|
| 397 |
+
max-width: 900px;
|
| 398 |
+
margin: 0 auto;
|
| 399 |
+
padding: 20px;
|
| 400 |
+
background-color: #f9f9f9;
|
| 401 |
+
}}
|
| 402 |
+
header {{
|
| 403 |
+
background-color: #84cc16;
|
| 404 |
+
color: white;
|
| 405 |
+
padding: 20px;
|
| 406 |
+
text-align: center;
|
| 407 |
+
border-radius: 8px;
|
| 408 |
+
margin-bottom: 30px;
|
| 409 |
+
}}
|
| 410 |
+
h1 {{
|
| 411 |
+
margin: 0;
|
| 412 |
+
font-size: 2em;
|
| 413 |
+
}}
|
| 414 |
+
h2 {{
|
| 415 |
+
border-bottom: 2px solid #84cc16;
|
| 416 |
+
padding-bottom: 10px;
|
| 417 |
+
color: #2f855a;
|
| 418 |
+
}}
|
| 419 |
+
h3 {{
|
| 420 |
+
color: #3f6212;
|
| 421 |
+
}}
|
| 422 |
+
.content {{
|
| 423 |
+
background-color: white;
|
| 424 |
+
padding: 25px;
|
| 425 |
+
border-radius: 8px;
|
| 426 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
|
| 427 |
+
}}
|
| 428 |
+
footer {{
|
| 429 |
+
margin-top: 30px;
|
| 430 |
+
text-align: center;
|
| 431 |
+
color: #666;
|
| 432 |
+
font-size: 0.9em;
|
| 433 |
+
}}
|
| 434 |
+
ul {{
|
| 435 |
+
margin-left: 20px;
|
| 436 |
+
}}
|
| 437 |
+
code {{
|
| 438 |
+
background-color: #f0f0f0;
|
| 439 |
+
padding: 2px 5px;
|
| 440 |
+
border-radius: 3px;
|
| 441 |
+
font-family: monospace;
|
| 442 |
+
}}
|
| 443 |
+
blockquote {{
|
| 444 |
+
border-left: 4px solid #84cc16;
|
| 445 |
+
margin-left: 0;
|
| 446 |
+
padding-left: 15px;
|
| 447 |
+
color: #555;
|
| 448 |
+
}}
|
| 449 |
+
li {{
|
| 450 |
+
margin-bottom: 10px;
|
| 451 |
+
}}
|
| 452 |
+
</style>
|
| 453 |
+
</head>
|
| 454 |
+
<body>
|
| 455 |
+
<header>
|
| 456 |
+
<h1>{title} - SEO Plan</h1>
|
| 457 |
+
<p>Generated on {datetime.now().strftime("%B %d, %Y at %H:%M")}</p>
|
| 458 |
+
</header>
|
| 459 |
+
<div class="content">
|
| 460 |
+
{markdown.markdown(content)}
|
| 461 |
+
</div>
|
| 462 |
+
<footer>
|
| 463 |
+
<p>Generated using Fermentation SEO Assistant</p>
|
| 464 |
+
</footer>
|
| 465 |
+
</body>
|
| 466 |
+
</html>
|
| 467 |
+
"""
|
| 468 |
+
return html_template
|
| 469 |
+
|
| 470 |
+
# Export the SEO plan as HTML and create download link
|
| 471 |
+
def export_html(content, topic):
|
| 472 |
+
if not content or content.startswith("⚠️") or content.startswith("🔄"):
|
| 473 |
+
return "Please generate an SEO plan first."
|
| 474 |
+
|
| 475 |
+
title = topic.strip().title()
|
| 476 |
+
html_content = generate_html_export(content, title)
|
| 477 |
+
|
| 478 |
+
# Create a safe filename
|
| 479 |
+
safe_filename = "".join([c if c.isalnum() or c in " -_" else "_" for c in title])
|
| 480 |
+
safe_filename = safe_filename.replace(" ", "_") + "_SEO_Plan.html"
|
| 481 |
+
|
| 482 |
+
# Write to file
|
| 483 |
+
with open(safe_filename, "w", encoding="utf-8") as f:
|
| 484 |
+
f.write(html_content)
|
| 485 |
+
|
| 486 |
+
return f"✅ HTML export saved as '{safe_filename}'"
|
| 487 |
+
|
| 488 |
+
# Function to update template
|
| 489 |
+
def save_custom_template(template_name, template_content):
|
| 490 |
+
if not template_name or not template_content:
|
| 491 |
+
return "⚠️ Please provide both a template name and content."
|
| 492 |
+
|
| 493 |
+
# Add to templates
|
| 494 |
+
TEMPLATES[template_name.lower()] = template_content
|
| 495 |
+
|
| 496 |
+
# Save to file
|
| 497 |
+
save_templates()
|
| 498 |
+
|
| 499 |
+
return f"✅ Template '{template_name}' saved successfully!"
|
| 500 |
+
|
| 501 |
+
# Function to update language settings
|
| 502 |
+
def save_language_settings(language_name, search_engines, localization_tips, keyword_examples):
|
| 503 |
+
if not language_name:
|
| 504 |
+
return "⚠️ Please provide a language name."
|
| 505 |
+
|
| 506 |
+
# Process keyword examples
|
| 507 |
+
if isinstance(keyword_examples, str):
|
| 508 |
+
keyword_list = [k.strip() for k in keyword_examples.split(",")]
|
| 509 |
+
else:
|
| 510 |
+
keyword_list = keyword_examples
|
| 511 |
+
|
| 512 |
+
# Add to languages
|
| 513 |
+
LANGUAGES[language_name] = {
|
| 514 |
+
"search_engines": search_engines.split(",") if isinstance(search_engines, str) else search_engines,
|
| 515 |
+
"localization_tips": localization_tips,
|
| 516 |
+
"keyword_examples": keyword_list
|
| 517 |
+
}
|
| 518 |
+
|
| 519 |
+
# Save to file
|
| 520 |
+
save_templates()
|
| 521 |
+
|
| 522 |
+
return f"✅ Language settings for '{language_name}' saved successfully!"
|
| 523 |
+
|
| 524 |
+
# Function to load template content
|
| 525 |
+
def load_template_content(template_name):
|
| 526 |
+
if template_name in TEMPLATES:
|
| 527 |
+
return TEMPLATES[template_name]
|
| 528 |
+
return ""
|
| 529 |
+
|
| 530 |
+
# Function to build prompt with language optimization
|
| 531 |
+
def build_prompt(topic, template_key="fermentation", language="English"):
|
| 532 |
+
# Get base template
|
| 533 |
+
if template_key in TEMPLATES:
|
| 534 |
+
template = TEMPLATES[template_key]
|
| 535 |
+
else:
|
| 536 |
+
template = TEMPLATES["fermentation"] # Default to fermentation
|
| 537 |
+
|
| 538 |
+
# Get language settings
|
| 539 |
+
lang_settings = LANGUAGES.get(language, LANGUAGES["English"])
|
| 540 |
+
|
| 541 |
+
# Add language-specific instructions
|
| 542 |
+
language_instructions = f"""
|
| 543 |
+
Additionally, optimize the SEO plan for {language} language users with these considerations:
|
| 544 |
+
|
| 545 |
+
1. **Target Search Engines:** {', '.join(lang_settings['search_engines'])}
|
| 546 |
+
2. **Localization Tips:** {lang_settings['localization_tips']}
|
| 547 |
+
3. **Keyword Patterns:** Consider these {language} keyword patterns: {', '.join(lang_settings['keyword_examples'])}
|
| 548 |
+
4. **Language-Specific SEO:** Adjust title length, meta description, and keyword density for {language} search engines
|
| 549 |
+
"""
|
| 550 |
+
|
| 551 |
+
# If not English, add language-specific instructions
|
| 552 |
+
if language != "English":
|
| 553 |
+
full_template = template + language_instructions
|
| 554 |
+
else:
|
| 555 |
+
full_template = template
|
| 556 |
+
|
| 557 |
+
# Format with the topic
|
| 558 |
+
return full_template.format(topic=topic)
|
| 559 |
+
|
| 560 |
# Function to generate SEO plan with proper error handling
|
| 561 |
+
def generate_seo_plan(topic, api_key, template_key="fermentation", language="English", temperature=0.7, max_tokens=4000):
|
| 562 |
# Input validation
|
| 563 |
if not topic.strip():
|
| 564 |
return "⚠️ Please enter a fermentation topic to generate an SEO plan."
|
|
|
|
| 584 |
)
|
| 585 |
|
| 586 |
# Update status
|
| 587 |
+
yield f"🧠 Building SEO prompt for your {template_key} topic in {language}..."
|
| 588 |
|
| 589 |
+
# Build the prompt with template and language
|
| 590 |
+
prompt = build_prompt(topic, template_key, language)
|
| 591 |
|
| 592 |
# Update status
|
| 593 |
yield "🚀 Generating SEO plan with Gemini 1.5 Pro..."
|
|
|
|
| 612 |
else:
|
| 613 |
yield f"⚠️ Error: {error_message}"
|
| 614 |
|
| 615 |
+
# Function to clear outputs
|
| 616 |
+
def clear_outputs():
|
| 617 |
+
return "", gr.update(value="")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 618 |
|
| 619 |
# Save API key to user's preferences
|
| 620 |
def save_api_key(api_key):
|
|
|
|
| 624 |
return "✅ API key saved successfully!"
|
| 625 |
return "⚠️ Please enter an API key to save"
|
| 626 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 627 |
# Define theme for better visual experience
|
| 628 |
custom_theme = gr.themes.Soft(
|
| 629 |
primary_hue="green",
|
|
|
|
| 646 |
overflow-y: auto;
|
| 647 |
border-left: 4px solid #84cc16;
|
| 648 |
padding-left: 15px;
|
| 649 |
+
background-color: #f8fafc;
|
| 650 |
border-radius: 6px;
|
| 651 |
transition: all 0.3s ease;
|
| 652 |
}
|
| 653 |
|
| 654 |
#seo-output-container:empty {
|
| 655 |
border-left-color: #e5e7eb;
|
| 656 |
+
background-color: #ffffff;
|
| 657 |
}
|
| 658 |
|
| 659 |
.loading-spinner {
|