-
Suggested Hashtags
-
- {% for tag in results.hashtags %}
- {{ tag }}
- {% endfor %}
-
+
+
+
"I love how easy it is to use. The interface is clean and intuitive, and the results are always top-notch."
+
- Mark T.
-
-
-
Suggested Tags
-
{{ results.tags|join:", " }}
+
+
+
"The best SEO tool I've ever used. It's saved me hours of research and helped me rank my videos higher than ever before."
+
- Emily R.
-{% endif %}
-{% endblock %}
+
+
+
+
+
+
Frequently Asked Questions
+
+
+
+
+
+
+
+
+
+ An SEO Content Generator is a tool that uses artificial intelligence to help you create search-engine-optimized content for your website or social media channels. By inputting a topic, you can generate relevant keywords, compelling titles, and other content to improve your search rankings and attract more traffic.
+
+
+
+
+
+
+
+ Using the generator is simple. Just choose your desired content type (Website SEO or YouTube SEO), enter a topic or keyword into the input field, and click the 'Generate' button. The tool will then provide you with a list of suggestions that you can copy and use in your content.
+
+
+
+
+
+
+
+ Yes, all keywords, titles, and hashtags generated by our tool are completely free to use. There are no hidden fees or subscription costs.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
About the Developer
+
This website was created by a passionate developer dedicated to building helpful and easy-to-use tools for content creators. With a background in web development and a passion for SEO, the goal is to empower creators with the resources they need to succeed.
+
+
+
+
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/core/views.py b/core/views.py
index af8c5da..fb4b5b0 100644
--- a/core/views.py
+++ b/core/views.py
@@ -1,4 +1,8 @@
from django.shortcuts import render
+from ai.local_ai_api import LocalAIApi
+import logging
+
+logger = logging.getLogger(__name__)
def home(request):
"""
@@ -7,18 +11,57 @@ def home(request):
context = {}
if request.method == 'POST':
topic = request.POST.get('topic', '').strip()
+ form_type = request.POST.get('form_type', 'website') # Default to website
+
context['topic'] = topic
+ context['form_type'] = form_type
if not topic:
- context['error'] = 'Please enter a video topic.'
+ context['error'] = 'Please enter a topic.'
else:
- # Mock data for demonstration purposes
- context['results'] = {
- 'title': f'🚀 The Ultimate Guide to {topic.title()} in 2025 | SEO Secrets',
- 'hashtags': ['#' + ''.join(word.capitalize() for word in topic.split()), '#YouTube', '#SEO', '#Viral', '#ContentCreation'],
- 'tags': [topic, f'{topic} tutorial`, `learn {topic}', 'how to', '2025', 'SEO tips', 'viral video']
- }
- context['meta_description'] = f'Get the best viral tags, hashtags, and titles for your video about {topic}. Boost your views with our AI-powered suggestions.'
- context['slug'] = f'viral-guide-{topic.lower().replace(" ", "-")}'
+ try:
+ if form_type == 'website':
+ prompt = {
+ "input": [
+ {"role": "system", "content": "You are an expert SEO content strategist. Generate a compelling blog post title and a list of relevant SEO keywords for a given topic. Return the result as a JSON object with two keys: 'title' and 'keywords'. The 'keywords' should be a list of strings."},
+ {"role": "user", "content": f"The topic is: {topic}"},
+ ],
+ "text": {"format": {"type": "json_object"}},
+ }
+ response = LocalAIApi.create_response(prompt)
+
+ if response.get("success"):
+ payload = LocalAIApi.decode_json_from_response(response)
+ if payload:
+ context['results'] = payload
+ else:
+ context['error'] = 'Failed to generate content. The AI response was not valid JSON.'
+ else:
+ logger.warning("AI error: %s", response.get("error"))
+ context['error'] = 'Failed to generate content due to an AI error.'
+
+ elif form_type == 'youtube':
+ prompt = {
+ "input": [
+ {"role": "system", "content": "You are a YouTube content expert. Generate a catchy title, a list of relevant keywords, and a list of hashtags for a given video topic. Return the result as a JSON object with three keys: 'title', 'keywords', and 'hashtags'. 'keywords' and 'hashtags' should be lists of strings."},
+ {"role": "user", "content": f"The topic is: {topic}"},
+ ],
+ "text": {"format": {"type": "json_object"}},
+ }
+ response = LocalAIApi.create_response(prompt)
+
+ if response.get("success"):
+ payload = LocalAIApi.decode_json_from_response(response)
+ if payload:
+ context['youtube_results'] = payload
+ else:
+ context['error'] = 'Failed to generate content. The AI response was not valid JSON.'
+ else:
+ logger.warning("AI error: %s", response.get("error"))
+ context['error'] = 'Failed to generate content due to an AI error.'
+
+ except Exception as e:
+ logger.error("An unexpected error occurred: %s", e)
+ context['error'] = 'An unexpected error occurred.'
return render(request, "core/index.html", context)
diff --git a/static/css/custom.css b/static/css/custom.css
index 2a01c49..9220be7 100644
--- a/static/css/custom.css
+++ b/static/css/custom.css
@@ -1,54 +1,53 @@
/* General Body Styles */
body {
- background-color: #0F3460; /* Dark Blue */
- color: #FFFFFF;
- font-family: 'Roboto', sans-serif;
+ background-color: #000000; /* Black */
+ color: #FFFFFF; /* White */
+ font-family: 'Playfair Display', serif;
}
-/* Hero Section */
-.hero {
+/* Remove background image overlay */
+body::before {
+ display: none;
+}
+
+/* Make sure content is on top of the overlay */
+.hero-section, .results-section {
position: relative;
- padding: 100px 0;
- text-align: center;
- background-image: url('../pasted-20251118-024426-e59dd4cc.jpg');
- background-size: cover;
- background-position: center;
- min-height: 100vh;
- display: flex;
- align-items: center;
- justify-content: center;
-}
-
-.hero::before {
- content: '';
- position: absolute;
- top: 0;
- left: 0;
- right: 0;
- bottom: 0;
- background: rgba(15, 52, 96, 0.6); /* Dark Blue overlay, slightly more transparent */
z-index: 1;
}
-.hero .container {
- position: relative;
- z-index: 2;
+
+/* Hero Section */
+.hero-section {
+ padding: 6rem 0;
+ text-align: center;
+ background-color: transparent;
}
+.hero-content {
+ background-color: rgba(255, 255, 255, 0.05); /* Subtle glass effect */
+ padding: 2rem;
+ border-radius: 15px;
+ display: inline-block;
+}
+
+
/* Typography */
-h1, .h1 {
- font-family: 'Poppins', sans-serif;
+h1, .h1, h2, .h2, h3, .h3, h4, .h4, h5, .h5, h6, .h6 {
+ font-family: 'Playfair Display', serif;
font-weight: 700;
color: #FFFFFF;
- font-size: 3.8rem; /* Slightly larger */
- margin-bottom: 1rem;
- text-shadow: 2px 2px 8px rgba(0, 0, 0, 0.7); /* Stylish shadow */
}
-p.lead {
- color: rgba(255, 255, 255, 0.9); /* Brighter lead text */
- margin-bottom: 2rem;
- text-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6); /* Subtle shadow */
+h1, .h1 {
+ font-size: 3.8rem;
+ margin-bottom: 1rem;
+ text-shadow: none;
+}
+
+p, .lead {
+ color: rgba(255, 255, 255, 0.9);
+ text-shadow: none;
}
/* Form Styles */
@@ -65,42 +64,41 @@ p.lead {
.form-control:focus {
background-color: rgba(255, 255, 255, 0.2);
- border-color: #E94560; /* Accent Pink/Red */
+ border-color: #FFFFFF;
color: #FFFFFF;
- box-shadow: 0 0 0 0.25rem rgba(233, 69, 96, 0.25);
+ box-shadow: 0 0 0 0.25rem rgba(255, 255, 255, 0.25);
}
/* Button Styles */
.btn-primary {
- background-color: #E94560; /* Accent Pink/Red */
- border-color: #E94560;
+ background-color: #FFFFFF;
+ border-color: #FFFFFF;
+ color: #000000;
padding: 1rem 2rem;
font-weight: 700;
transition: background-color 0.3s ease, border-color 0.3s ease;
}
.btn-primary:hover {
- background-color: #c73049;
- border-color: #c73049;
+ background-color: #CCCCCC;
+ border-color: #CCCCCC;
}
/* Results Section */
.results-section {
- background-color: #1A1A2E; /* Deep Navy */
- padding: 4rem;
+ background-color: rgba(255, 255, 255, 0.05); /* Subtle glass effect */
+ padding: 2rem;
border-radius: 15px;
- margin-top: 3rem;
+ margin-top: 2rem;
border: 1px solid rgba(255, 255, 255, 0.1);
}
.results-section h2 {
- font-family: 'Poppins', sans-serif;
- color: #E94560; /* Accent Pink/Red */
+ color: #FFFFFF;
margin-bottom: 1.5rem;
}
.results-section h3 {
- font-family: 'Poppins', sans-serif;
font-size: 1.5rem;
color: #FFFFFF;
margin-top: 1.5rem;
@@ -110,9 +108,7 @@ p.lead {
.generated-title {
font-size: 1.75rem;
font-weight: bold;
- background: -webkit-linear-gradient(45deg, #E94560, #FFC700);
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
+ color: #FFFFFF;
}
.hashtag {
@@ -125,3 +121,121 @@ p.lead {
margin-bottom: 0.5rem;
font-size: 0.9rem;
}
+
+
+/* Custom CSS for the new SEO generator */
+.result-item {
+ margin-bottom: 2rem;
+}
+
+.result-item h3 {
+ color: #FFFFFF;
+}
+
+.result-item .form-control {
+ background-color: #333333;
+ border-color: #555555;
+ color: #FFFFFF;
+ min-height: 50px;
+}
+
+.result-item .btn-outline-secondary {
+ color: #FFFFFF;
+ border-color: #FFFFFF;
+}
+
+.result-item .btn-outline-secondary:hover {
+ background-color: #FFFFFF;
+ color: #000000;
+}
+
+/* Tab Styles */
+.nav-tabs {
+ border-bottom: 1px solid #FFFFFF;
+}
+
+.nav-tabs .nav-link {
+ background-color: transparent;
+ border: none;
+ color: rgba(255, 255, 255, 0.7);
+}
+
+.nav-tabs .nav-link.active {
+ color: #000000;
+ background-color: #FFFFFF;
+ border-color: #FFFFFF;
+}
+
+.tab-content {
+ padding-top: 1rem;
+}
+
+/* Section Title */
+.section-title {
+ font-family: 'Playfair Display', serif;
+ font-weight: 700;
+ color: #FFFFFF;
+ font-size: 2.5rem;
+ margin-bottom: 2rem;
+ text-shadow: none;
+}
+
+/* Review Section */
+.review-card {
+ background-color: rgba(255, 255, 255, 0.05);
+ padding: 2rem;
+ border-radius: 15px;
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ height: 100%;
+}
+
+.review-text {
+ font-style: italic;
+ color: rgba(255, 255, 255, 0.9);
+}
+
+.review-author {
+ font-weight: 700;
+ color: #FFFFFF;
+ text-align: right;
+}
+
+/* FAQ Section */
+.accordion-item {
+ background-color: rgba(255, 255, 255, 0.05);
+ border: 1px solid rgba(255, 255, 255, 0.1);
+ margin-bottom: 1rem;
+ border-radius: 15px !important;
+}
+
+.accordion-button {
+ background-color: transparent;
+ color: #FFFFFF;
+ font-family: 'Playfair Display', serif;
+ font-weight: 700;
+ border: none;
+ box-shadow: none;
+}
+
+.accordion-button:not(.collapsed) {
+ color: #FFFFFF;
+ background-color: transparent;
+}
+
+.accordion-body {
+ color: rgba(255, 255, 255, 0.9);
+}
+
+/* About Section */
+.about-card {
+ background-color: rgba(255, 255, 255, 0.05);
+ padding: 2rem;
+ border-radius: 15px;
+ border: 1px solid rgba(255, 255, 255, 0.1);
+}
+
+.about-text {
+ color: rgba(255, 255, 255, 0.9);
+ font-size: 1.1rem;
+ line-height: 1.8;
+}