diff --git a/lib/ai_marketing_tools/.ai_backlinking.py.swp b/lib/ai_marketing_tools/.ai_backlinking.py.swp
deleted file mode 100644
index 887420ef..00000000
Binary files a/lib/ai_marketing_tools/.ai_backlinking.py.swp and /dev/null differ
diff --git a/lib/ai_marketing_tools/README.md b/lib/ai_marketing_tools/ai_backlinker/README.md
similarity index 100%
rename from lib/ai_marketing_tools/README.md
rename to lib/ai_marketing_tools/ai_backlinker/README.md
diff --git a/lib/ai_marketing_tools/ai_backlinking.py b/lib/ai_marketing_tools/ai_backlinker/ai_backlinking.py
similarity index 100%
rename from lib/ai_marketing_tools/ai_backlinking.py
rename to lib/ai_marketing_tools/ai_backlinker/ai_backlinking.py
diff --git a/lib/ai_marketing_tools/backlinking_ui_streamlit.py b/lib/ai_marketing_tools/ai_backlinker/backlinking_ui_streamlit.py
similarity index 94%
rename from lib/ai_marketing_tools/backlinking_ui_streamlit.py
rename to lib/ai_marketing_tools/ai_backlinker/backlinking_ui_streamlit.py
index 3b57319d..e5222671 100644
--- a/lib/ai_marketing_tools/backlinking_ui_streamlit.py
+++ b/lib/ai_marketing_tools/ai_backlinker/backlinking_ui_streamlit.py
@@ -1,7 +1,7 @@
import streamlit as st
import pandas as pd
from st_aggrid import AgGrid, GridOptionsBuilder, GridUpdateMode
-from lib.ai_marketing_tools.ai_backlinking import find_backlink_opportunities, compose_personalized_email
+from lib.ai_marketing_tools.ai_backlinker.ai_backlinking import find_backlink_opportunities, compose_personalized_email
# Streamlit UI function
diff --git a/lib/ai_marketing_tools/ai_google_ads_generator/README.md b/lib/ai_marketing_tools/ai_google_ads_generator/README.md
new file mode 100644
index 00000000..129194c8
--- /dev/null
+++ b/lib/ai_marketing_tools/ai_google_ads_generator/README.md
@@ -0,0 +1,370 @@
+Google Ads Generator
+Google Ads Generator Logo
+
+Overview
+The Google Ads Generator is an AI-powered tool designed to create high-converting Google Ads based on industry best practices. This tool helps marketers, business owners, and advertising professionals create optimized ad campaigns that maximize ROI and conversion rates.
+
+By leveraging advanced AI algorithms and proven advertising frameworks, the Google Ads Generator creates compelling ad copy, suggests optimal keywords, generates relevant extensions, and provides performance predictions—all tailored to your specific business needs and target audience.
+
+Table of Contents
+Features
+Getting Started
+User Interface
+Ad Creation Process
+Ad Types
+Quality Analysis
+Performance Simulation
+Best Practices
+Export Options
+Advanced Features
+Technical Details
+FAQ
+Troubleshooting
+Updates and Roadmap
+Features
+Core Features
+AI-Powered Ad Generation: Create compelling, high-converting Google Ads in seconds
+Multiple Ad Types: Support for Responsive Search Ads, Expanded Text Ads, Call-Only Ads, and Dynamic Search Ads
+Industry-Specific Templates: Tailored templates for 20+ industries
+Ad Extensions Generator: Automatically create Sitelinks, Callouts, and Structured Snippets
+Quality Score Analysis: Comprehensive scoring based on Google's quality factors
+Performance Prediction: Estimate CTR, conversion rates, and ROI
+A/B Testing: Generate multiple variations for testing
+Export Options: Export to CSV, Excel, Google Ads Editor CSV, and JSON
+Advanced Features
+Keyword Research Integration: Find high-performing keywords for your ads
+Competitor Analysis: Analyze competitor ads and identify opportunities
+Landing Page Suggestions: Recommendations for landing page optimization
+Budget Optimization: Suggestions for optimal budget allocation
+Ad Schedule Recommendations: Identify the best times to run your ads
+Audience Targeting Suggestions: Recommendations for demographic targeting
+Local Ad Optimization: Special features for local businesses
+E-commerce Ad Features: Product-specific ad generation
+Getting Started
+Prerequisites
+Alwrity AI Writer platform
+Basic understanding of Google Ads concepts
+Information about your business, products/services, and target audience
+Accessing the Tool
+Navigate to the Alwrity AI Writer platform
+Select "AI Google Ads Generator" from the tools menu
+Follow the guided setup process
+User Interface
+The Google Ads Generator features a user-friendly, tabbed interface designed to guide you through the ad creation process:
+
+Tab 1: Ad Creation
+This is where you'll input your business information and ad requirements:
+
+Business Information: Company name, industry, products/services
+Campaign Goals: Select from options like brand awareness, lead generation, sales, etc.
+Target Audience: Define your ideal customer
+Ad Type Selection: Choose from available ad formats
+USP and Benefits: Input your unique selling propositions and key benefits
+Keywords: Add target keywords or generate suggestions
+Landing Page URL: Specify where users will go after clicking your ad
+Budget Information: Set daily/monthly budget for performance predictions
+Tab 2: Ad Performance
+After generating ads, this tab provides detailed analysis:
+
+Quality Score: Overall score (1-10) with detailed breakdown
+Strengths & Improvements: What's good and what could be better
+Keyword Relevance: Analysis of keyword usage in ad elements
+CTR Prediction: Estimated click-through rate based on ad quality
+Conversion Potential: Estimated conversion rate
+Mobile Friendliness: Assessment of how well the ad performs on mobile
+Ad Policy Compliance: Check for potential policy violations
+Tab 3: Ad History
+Keep track of your generated ads:
+
+Saved Ads: Previously generated and saved ads
+Favorites: Ads you've marked as favorites
+Version History: Track changes and iterations
+Performance Notes: Add notes about real-world performance
+Tab 4: Best Practices
+Educational resources to improve your ads:
+
+Industry Guidelines: Best practices for your specific industry
+Ad Type Tips: Specific guidance for each ad type
+Quality Score Optimization: How to improve quality score
+Extension Strategies: How to effectively use ad extensions
+A/B Testing Guide: How to test and optimize your ads
+Ad Creation Process
+Step 1: Define Your Campaign
+Select your industry from the dropdown menu
+Choose your primary campaign goal
+Define your target audience
+Set your budget parameters
+Step 2: Input Business Details
+Enter your business name
+Provide your website URL
+Input your unique selling propositions
+List key product/service benefits
+Add any promotional offers or discounts
+Step 3: Keyword Selection
+Enter your primary keywords
+Use the integrated keyword research tool to find additional keywords
+Select keyword match types (broad, phrase, exact)
+Review keyword competition and volume metrics
+Step 4: Ad Type Selection
+Choose your preferred ad type
+Review the requirements and limitations for that ad type
+Select any additional features specific to that ad type
+Step 5: Generate Ads
+Click the "Generate Ads" button
+Review the generated ads
+Request variations if needed
+Save your favorite versions
+Step 6: Add Extensions
+Select which extension types to include
+Review and edit the generated extensions
+Add any custom extensions
+Step 7: Analyze and Optimize
+Review the quality score and analysis
+Make suggested improvements
+Regenerate ads if necessary
+Compare different versions
+Step 8: Export
+Choose your preferred export format
+Select which ads to include
+Download the file for import into Google Ads
+Ad Types
+Responsive Search Ads (RSA)
+The most flexible and recommended ad type, featuring:
+
+Up to 15 headlines (3 shown at a time)
+Up to 4 descriptions (2 shown at a time)
+Dynamic combination of elements based on performance
+Automatic testing of different combinations
+Expanded Text Ads (ETA)
+A more controlled ad format with:
+
+3 headlines
+2 descriptions
+Display URL with two path fields
+Fixed layout with no dynamic combinations
+Call-Only Ads
+Designed to drive phone calls rather than website visits:
+
+Business name
+Phone number
+Call-to-action text
+Description lines
+Verification URL (not shown to users)
+Dynamic Search Ads (DSA)
+Ads that use your website content to target relevant searches:
+
+Dynamic headline generation based on search queries
+Custom descriptions
+Landing page selection based on website content
+Requires website URL for crawling
+Quality Analysis
+Our comprehensive quality analysis evaluates your ads based on factors that influence Google's Quality Score:
+
+Headline Analysis
+Keyword Usage: Presence of keywords in headlines
+Character Count: Optimal length for visibility
+Power Words: Use of emotionally compelling words
+Clarity: Clear communication of value proposition
+Call to Action: Presence of action-oriented language
+Description Analysis
+Keyword Density: Optimal keyword usage
+Benefit Focus: Clear articulation of benefits
+Feature Inclusion: Mention of key features
+Urgency Elements: Time-limited offers or scarcity
+Call to Action: Clear next steps for the user
+URL Path Analysis
+Keyword Inclusion: Relevant keywords in display paths
+Readability: Clear, understandable paths
+Relevance: Connection to landing page content
+Overall Ad Relevance
+Keyword-to-Ad Relevance: Alignment between keywords and ad copy
+Ad-to-Landing Page Relevance: Consistency across the user journey
+Intent Match: Alignment with search intent
+Performance Simulation
+Our tool provides data-driven performance predictions based on:
+
+Click-Through Rate (CTR) Prediction
+Industry benchmarks
+Ad quality factors
+Keyword competition
+Ad position estimates
+Conversion Rate Prediction
+Industry averages
+Landing page quality
+Offer strength
+Call-to-action effectiveness
+Cost Estimation
+Keyword competition
+Quality Score impact
+Industry CPC averages
+Budget allocation
+ROI Calculation
+Estimated clicks
+Predicted conversions
+Average conversion value
+Cost projections
+Best Practices
+Our tool incorporates these Google Ads best practices:
+
+Headline Best Practices
+Include primary keywords in at least 2 headlines
+Use numbers and statistics when relevant
+Address user pain points directly
+Include your unique selling proposition
+Create a sense of urgency when appropriate
+Keep headlines under 30 characters for full visibility
+Use title case for better readability
+Include at least one call-to-action headline
+Description Best Practices
+Include primary and secondary keywords naturally
+Focus on benefits, not just features
+Address objections proactively
+Include specific offers or promotions
+End with a clear call to action
+Use all available character space (90 characters per description)
+Maintain consistent messaging with headlines
+Include trust signals (guarantees, social proof, etc.)
+Extension Best Practices
+Create at least 8 sitelinks for maximum visibility
+Use callouts to highlight additional benefits
+Include structured snippets relevant to your industry
+Ensure extensions don't duplicate headline content
+Make each extension unique and valuable
+Use specific, action-oriented language
+Keep sitelink text under 25 characters for mobile visibility
+Ensure landing pages for sitelinks are relevant and optimized
+Campaign Structure Best Practices
+Group closely related keywords together
+Create separate ad groups for different themes
+Align ad copy closely with keywords in each ad group
+Use a mix of match types for each keyword
+Include negative keywords to prevent irrelevant clicks
+Create separate campaigns for different goals or audiences
+Set appropriate bid adjustments for devices, locations, and schedules
+Implement conversion tracking for performance measurement
+Export Options
+The Google Ads Generator offers multiple export formats to fit your workflow:
+
+CSV Format
+Standard CSV format compatible with most spreadsheet applications
+Includes all ad elements and extensions
+Contains quality score and performance predictions
+Suitable for analysis and record-keeping
+Excel Format
+Formatted Excel workbook with multiple sheets
+Separate sheets for ads, extensions, and analysis
+Includes charts and visualizations of predicted performance
+Color-coded quality indicators
+Google Ads Editor CSV
+Specially formatted CSV for direct import into Google Ads Editor
+Follows Google's required format specifications
+Includes all necessary fields for campaign creation
+Ready for immediate upload to Google Ads Editor
+JSON Format
+Structured data format for programmatic use
+Complete ad data in machine-readable format
+Suitable for integration with other marketing tools
+Includes all metadata and analysis results
+Advanced Features
+Keyword Research Integration
+Access to keyword volume data
+Competition analysis
+Cost-per-click estimates
+Keyword difficulty scores
+Seasonal trend information
+Question-based keyword suggestions
+Long-tail keyword recommendations
+Competitor Analysis
+Identify competitors bidding on similar keywords
+Analyze competitor ad copy and messaging
+Identify gaps and opportunities
+Benchmark your ads against competitors
+Receive suggestions for differentiation
+Landing Page Suggestions
+Alignment with ad messaging
+Key elements to include
+Conversion optimization tips
+Mobile responsiveness recommendations
+Page speed improvement suggestions
+Call-to-action placement recommendations
+Local Ad Optimization
+Location extension suggestions
+Local keyword recommendations
+Geo-targeting strategies
+Local offer suggestions
+Community-focused messaging
+Location-specific call-to-actions
+Technical Details
+System Requirements
+Modern web browser (Chrome, Firefox, Safari, Edge)
+Internet connection
+Access to Alwrity AI Writer platform
+Data Privacy
+No permanent storage of business data
+Secure processing of all inputs
+Option to save ads to your account
+Compliance with data protection regulations
+API Integration
+Available API endpoints for programmatic access
+Documentation for developers
+Rate limits and authentication requirements
+Sample code for common use cases
+FAQ
+General Questions
+Q: How accurate are the performance predictions? A: Performance predictions are based on industry benchmarks and Google's published data. While they provide a good estimate, actual performance may vary based on numerous factors including competition, seasonality, and market conditions.
+
+Q: Can I edit the generated ads? A: Yes, all generated ads can be edited before export. You can modify headlines, descriptions, paths, and extensions to better fit your needs.
+
+Q: How many ads can I generate? A: The tool allows unlimited ad generation within your Alwrity subscription limits.
+
+Q: Are the generated ads compliant with Google's policies? A: The tool is designed to create policy-compliant ads, but we recommend reviewing Google's latest advertising policies as they may change over time.
+
+Technical Questions
+Q: Can I import my existing ads for optimization? A: Currently, the tool does not support importing existing ads, but this feature is on our roadmap.
+
+Q: How do I import the exported files into Google Ads? A: For Google Ads Editor CSV files, open Google Ads Editor, go to File > Import, and select your exported file. For other formats, you may need to manually create campaigns using the generated content.
+
+Q: Can I schedule automatic ad generation? A: Automated scheduling is not currently available but is planned for a future release.
+
+Troubleshooting
+Common Issues
+Issue: Generated ads don't include my keywords Solution: Ensure your keywords are relevant to your business description and offerings. Try using more specific keywords or providing more detailed business information.
+
+Issue: Quality score is consistently low Solution: Review the improvement suggestions in the Ad Performance tab. Common issues include keyword relevance, landing page alignment, and benefit clarity.
+
+Issue: Export file isn't importing correctly into Google Ads Editor Solution: Ensure you're selecting the "Google Ads Editor CSV" export format. If problems persist, check for special characters in your ad copy that might be causing formatting issues.
+
+Issue: Performance predictions seem unrealistic Solution: Adjust your industry selection and budget information to get more accurate predictions. Consider providing more specific audience targeting information.
+
+Updates and Roadmap
+Recent Updates
+Added support for Performance Max campaign recommendations
+Improved keyword research integration
+Enhanced mobile ad optimization
+Added 5 new industry templates
+Improved quality score algorithm
+Coming Soon
+Competitor ad analysis tool
+A/B testing performance simulator
+Landing page builder integration
+Automated ad scheduling recommendations
+Video ad script generator
+Google Shopping ad support
+Multi-language ad generation
+Custom template builder
+Support
+For additional help with the Google Ads Generator:
+
+Visit our Help Center
+Email support at support@example.com
+Join our Community Forum
+License
+The Google Ads Generator is part of the Alwrity AI Writer platform and is subject to the platform's terms of service and licensing agreements.
+
+Acknowledgments
+Google Ads API documentation
+Industry best practices from leading digital marketing experts
+User feedback and feature requests
+Last updated: [Current Date]
+
+Version: 1.0.0
\ No newline at end of file
diff --git a/lib/ai_marketing_tools/ai_google_ads_generator/__init__.py b/lib/ai_marketing_tools/ai_google_ads_generator/__init__.py
new file mode 100644
index 00000000..634e577f
--- /dev/null
+++ b/lib/ai_marketing_tools/ai_google_ads_generator/__init__.py
@@ -0,0 +1,9 @@
+"""
+Google Ads Generator Module
+
+This module provides functionality for generating high-converting Google Ads.
+"""
+
+from .google_ads_generator import write_google_ads
+
+__all__ = ["write_google_ads"]
\ No newline at end of file
diff --git a/lib/ai_marketing_tools/ai_google_ads_generator/ad_analyzer.py b/lib/ai_marketing_tools/ai_google_ads_generator/ad_analyzer.py
new file mode 100644
index 00000000..1680a271
--- /dev/null
+++ b/lib/ai_marketing_tools/ai_google_ads_generator/ad_analyzer.py
@@ -0,0 +1,327 @@
+"""
+Ad Analyzer Module
+
+This module provides functions for analyzing and scoring Google Ads.
+"""
+
+import re
+from typing import Dict, List, Any, Tuple
+import random
+from urllib.parse import urlparse
+
+def analyze_ad_quality(ad: Dict, primary_keywords: List[str], secondary_keywords: List[str],
+business_name: str, call_to_action: str) -> Dict:
+"""
+Analyze the quality of a Google Ad based on best practices.
+
+Args:
+ad: Dictionary containing ad details
+primary_keywords: List of primary keywords
+secondary_keywords: List of secondary keywords
+business_name: Name of the business
+call_to_action: Call to action text
+
+Returns:
+Dictionary with analysis results
+"""
+# Initialize results
+strengths = []
+improvements = []
+
+# Get ad components
+headlines = ad.get("headlines", [])
+descriptions = ad.get("descriptions", [])
+path1 = ad.get("path1", "")
+path2 = ad.get("path2", "")
+
+# Check headline count
+if len(headlines) >= 10:
+strengths.append("Good number of headlines (10+) for optimization")
+elif len(headlines) >= 5:
+strengths.append("Adequate number of headlines for testing")
+else:
+improvements.append("Add more headlines (aim for 10+) to give Google's algorithm more options")
+
+# Check description count
+if len(descriptions) >= 4:
+strengths.append("Good number of descriptions (4+) for optimization")
+elif len(descriptions) >= 2:
+strengths.append("Adequate number of descriptions for testing")
+else:
+improvements.append("Add more descriptions (aim for 4+) to give Google's algorithm more options")
+
+# Check headline length
+long_headlines = [h for h in headlines if len(h) > 30]
+if long_headlines:
+improvements.append(f"{len(long_headlines)} headline(s) exceed 30 characters and may be truncated")
+else:
+strengths.append("All headlines are within the recommended length")
+
+# Check description length
+long_descriptions = [d for d in descriptions if len(d) > 90]
+if long_descriptions:
+improvements.append(f"{len(long_descriptions)} description(s) exceed 90 characters and may be truncated")
+else:
+strengths.append("All descriptions are within the recommended length")
+
+# Check keyword usage in headlines
+headline_keywords = []
+for kw in primary_keywords:
+if any(kw.lower() in h.lower() for h in headlines):
+headline_keywords.append(kw)
+
+if len(headline_keywords) == len(primary_keywords):
+strengths.append("All primary keywords are used in headlines")
+elif headline_keywords:
+strengths.append(f"{len(headline_keywords)} out of {len(primary_keywords)} primary keywords used in headlines")
+missing_kw = [kw for kw in primary_keywords if kw not in headline_keywords]
+improvements.append(f"Add these primary keywords to headlines: {', '.join(missing_kw)}")
+else:
+improvements.append("No primary keywords found in headlines - add keywords to improve relevance")
+
+# Check keyword usage in descriptions
+desc_keywords = []
+for kw in primary_keywords:
+if any(kw.lower() in d.lower() for d in descriptions):
+desc_keywords.append(kw)
+
+if len(desc_keywords) == len(primary_keywords):
+strengths.append("All primary keywords are used in descriptions")
+elif desc_keywords:
+strengths.append(f"{len(desc_keywords)} out of {len(primary_keywords)} primary keywords used in descriptions")
+missing_kw = [kw for kw in primary_keywords if kw not in desc_keywords]
+improvements.append(f"Add these primary keywords to descriptions: {', '.join(missing_kw)}")
+else:
+improvements.append("No primary keywords found in descriptions - add keywords to improve relevance")
+
+# Check for business name
+if any(business_name.lower() in h.lower() for h in headlines):
+strengths.append("Business name is included in headlines")
+else:
+improvements.append("Consider adding your business name to at least one headline")
+
+# Check for call to action
+if any(call_to_action.lower() in h.lower() for h in headlines) or any(call_to_action.lower() in d.lower() for d in descriptions):
+strengths.append("Call to action is included in the ad")
+else:
+improvements.append(f"Add your call to action '{call_to_action}' to at least one headline or description")
+
+# Check for numbers and statistics
+has_numbers = any(bool(re.search(r'\d+', h)) for h in headlines) or any(bool(re.search(r'\d+', d)) for d in descriptions)
+if has_numbers:
+strengths.append("Ad includes numbers or statistics which can improve CTR")
+else:
+improvements.append("Consider adding numbers or statistics to increase credibility and CTR")
+
+# Check for questions
+has_questions = any('?' in h for h in headlines) or any('?' in d for d in descriptions)
+if has_questions:
+strengths.append("Ad includes questions which can engage users")
+else:
+improvements.append("Consider adding a question to engage users")
+
+# Check for emotional triggers
+emotional_words = ['you', 'free', 'because', 'instantly', 'new', 'save', 'proven', 'guarantee', 'love', 'discover']
+has_emotional = any(any(word in h.lower() for word in emotional_words) for h in headlines) or \
+any(any(word in d.lower() for word in emotional_words) for d in descriptions)
+
+if has_emotional:
+strengths.append("Ad includes emotional trigger words which can improve engagement")
+else:
+improvements.append("Consider adding emotional trigger words to increase engagement")
+
+# Check for path relevance
+if any(kw.lower() in path1.lower() or kw.lower() in path2.lower() for kw in primary_keywords):
+strengths.append("Display URL paths include keywords which improves relevance")
+else:
+improvements.append("Add keywords to your display URL paths to improve relevance")
+
+# Return the analysis results
+return {
+"strengths": strengths,
+"improvements": improvements
+}
+
+def calculate_quality_score(ad: Dict, primary_keywords: List[str], landing_page: str, ad_type: str) -> Dict:
+"""
+Calculate a quality score for a Google Ad based on best practices.
+
+Args:
+ad: Dictionary containing ad details
+primary_keywords: List of primary keywords
+landing_page: Landing page URL
+ad_type: Type of Google Ad
+
+Returns:
+Dictionary with quality score components
+"""
+# Initialize scores
+keyword_relevance = 0
+ad_relevance = 0
+cta_effectiveness = 0
+landing_page_relevance = 0
+
+# Get ad components
+headlines = ad.get("headlines", [])
+descriptions = ad.get("descriptions", [])
+path1 = ad.get("path1", "")
+path2 = ad.get("path2", "")
+
+# Calculate keyword relevance (0-10)
+# Check if keywords are in headlines, descriptions, and paths
+keyword_in_headline = sum(1 for kw in primary_keywords if any(kw.lower() in h.lower() for h in headlines))
+keyword_in_description = sum(1 for kw in primary_keywords if any(kw.lower() in d.lower() for d in descriptions))
+keyword_in_path = sum(1 for kw in primary_keywords if kw.lower() in path1.lower() or kw.lower() in path2.lower())
+
+# Calculate score based on keyword presence
+if len(primary_keywords) > 0:
+headline_score = min(10, (keyword_in_headline / len(primary_keywords)) * 10)
+description_score = min(10, (keyword_in_description / len(primary_keywords)) * 10)
+path_score = min(10, (keyword_in_path / len(primary_keywords)) * 10)
+
+# Weight the scores (headlines most important)
+keyword_relevance = (headline_score * 0.6) + (description_score * 0.3) + (path_score * 0.1)
+else:
+keyword_relevance = 5 # Default score if no keywords provided
+
+# Calculate ad relevance (0-10)
+# Check for ad structure and content quality
+
+# Check headline count and length
+headline_count_score = min(10, (len(headlines) / 10) * 10) # Ideal: 10+ headlines
+headline_length_score = 10 - min(10, (sum(1 for h in headlines if len(h) > 30) / max(1, len(headlines))) * 10)
+
+# Check description count and length
+description_count_score = min(10, (len(descriptions) / 4) * 10) # Ideal: 4+ descriptions
+description_length_score = 10 - min(10, (sum(1 for d in descriptions if len(d) > 90) / max(1, len(descriptions))) * 10)
+
+# Check for emotional triggers, questions, numbers
+emotional_words = ['you', 'free', 'because', 'instantly', 'new', 'save', 'proven', 'guarantee', 'love', 'discover']
+emotional_score = min(10, sum(1 for h in headlines if any(word in h.lower() for word in emotional_words)) +
+sum(1 for d in descriptions if any(word in d.lower() for word in emotional_words)))
+
+question_score = min(10, (sum(1 for h in headlines if '?' in h) + sum(1 for d in descriptions if '?' in d)) * 2)
+
+number_score = min(10, (sum(1 for h in headlines if bool(re.search(r'\d+', h))) +
+sum(1 for d in descriptions if bool(re.search(r'\d+', d)))) * 2)
+
+# Calculate overall ad relevance score
+ad_relevance = (headline_count_score * 0.15) + (headline_length_score * 0.15) + \
+(description_count_score * 0.15) + (description_length_score * 0.15) + \
+(emotional_score * 0.2) + (question_score * 0.1) + (number_score * 0.1)
+
+# Calculate CTA effectiveness (0-10)
+# Check for clear call to action
+cta_phrases = ['get', 'buy', 'shop', 'order', 'sign up', 'register', 'download', 'learn', 'discover', 'find', 'call',
+'contact', 'request', 'start', 'try', 'join', 'subscribe', 'book', 'schedule', 'apply']
+
+cta_in_headline = any(any(phrase in h.lower() for phrase in cta_phrases) for h in headlines)
+cta_in_description = any(any(phrase in d.lower() for phrase in cta_phrases) for d in descriptions)
+
+if cta_in_headline and cta_in_description:
+cta_effectiveness = 10
+elif cta_in_headline:
+cta_effectiveness = 8
+elif cta_in_description:
+cta_effectiveness = 7
+else:
+cta_effectiveness = 4
+
+# Calculate landing page relevance (0-10)
+# In a real implementation, this would analyze the landing page content
+# For this example, we'll use a simplified approach
+
+if landing_page:
+# Check if domain seems relevant to keywords
+domain = urlparse(landing_page).netloc
+
+# Check if keywords are in the domain or path
+keyword_in_url = any(kw.lower() in landing_page.lower() for kw in primary_keywords)
+
+# Check if URL structure seems appropriate
+has_https = landing_page.startswith('https://')
+
+# Calculate landing page score
+landing_page_relevance = 5 # Base score
+
+if keyword_in_url:
+landing_page_relevance += 3
+
+if has_https:
+landing_page_relevance += 2
+
+# Cap at 10
+landing_page_relevance = min(10, landing_page_relevance)
+else:
+landing_page_relevance = 5 # Default score if no landing page provided
+
+# Calculate overall quality score (0-10)
+overall_score = (keyword_relevance * 0.4) + (ad_relevance * 0.3) + (cta_effectiveness * 0.2) + (landing_page_relevance * 0.1)
+
+# Calculate estimated CTR based on quality score
+# This is a simplified model - in reality, CTR depends on many factors
+base_ctr = {
+"Responsive Search Ad": 3.17,
+"Expanded Text Ad": 2.83,
+"Call-Only Ad": 3.48,
+"Dynamic Search Ad": 2.69
+}.get(ad_type, 3.0)
+
+# Adjust CTR based on quality score (±50%)
+quality_factor = (overall_score - 5) / 5 # -1 to 1
+estimated_ctr = base_ctr * (1 + (quality_factor * 0.5))
+
+# Calculate estimated conversion rate
+# Again, this is simplified - actual conversion rates depend on many factors
+base_conversion_rate = 3.75 # Average conversion rate for search ads
+
+# Adjust conversion rate based on quality score (±40%)
+estimated_conversion_rate = base_conversion_rate * (1 + (quality_factor * 0.4))
+
+# Return the quality score components
+return {
+"keyword_relevance": round(keyword_relevance, 1),
+"ad_relevance": round(ad_relevance, 1),
+"cta_effectiveness": round(cta_effectiveness, 1),
+"landing_page_relevance": round(landing_page_relevance, 1),
+"overall_score": round(overall_score, 1),
+"estimated_ctr": round(estimated_ctr, 2),
+"estimated_conversion_rate": round(estimated_conversion_rate, 2)
+}
+
+def analyze_keyword_relevance(keywords: List[str], ad_text: str) -> Dict:
+"""
+Analyze the relevance of keywords to ad text.
+
+Args:
+keywords: List of keywords to analyze
+ad_text: Combined ad text (headlines and descriptions)
+
+Returns:
+Dictionary with keyword relevance analysis
+"""
+results = {}
+
+for keyword in keywords:
+# Check if keyword is in ad text
+is_present = keyword.lower() in ad_text.lower()
+
+# Check if keyword is in the first 100 characters
+is_in_beginning = keyword.lower() in ad_text.lower()[:100]
+
+# Count occurrences
+occurrences = ad_text.lower().count(keyword.lower())
+
+# Calculate density
+density = (occurrences * len(keyword)) / len(ad_text) * 100 if len(ad_text) > 0 else 0
+
+# Store results
+results[keyword] = {
+"present": is_present,
+"in_beginning": is_in_beginning,
+"occurrences": occurrences,
+"density": round(density, 2),
+"optimal_density": 0.5 <= density <= 2.5
+}
+
+return results
\ No newline at end of file
diff --git a/lib/ai_marketing_tools/ai_google_ads_generator/ad_extensions_generator.py b/lib/ai_marketing_tools/ai_google_ads_generator/ad_extensions_generator.py
new file mode 100644
index 00000000..83b733fa
--- /dev/null
+++ b/lib/ai_marketing_tools/ai_google_ads_generator/ad_extensions_generator.py
@@ -0,0 +1,320 @@
+"""
+Ad Extensions Generator Module
+
+This module provides functions for generating various types of Google Ads extensions.
+"""
+
+from typing import Dict, List, Any, Optional
+import re
+from ...gpt_providers.text_generation.main_text_generation import llm_text_gen
+
+def generate_extensions(business_name: str, business_description: str, industry: str,
+primary_keywords: List[str], unique_selling_points: List[str],
+landing_page: str) -> Dict:
+"""
+Generate a complete set of ad extensions based on business information.
+
+Args:
+business_name: Name of the business
+business_description: Description of the business
+industry: Industry of the business
+primary_keywords: List of primary keywords
+unique_selling_points: List of unique selling points
+landing_page: Landing page URL
+
+Returns:
+Dictionary with generated extensions
+"""
+# Generate sitelinks
+sitelinks = generate_sitelinks(business_name, business_description, industry, primary_keywords, landing_page)
+
+# Generate callouts
+callouts = generate_callouts(business_name, unique_selling_points, industry)
+
+# Generate structured snippets
+snippets = generate_structured_snippets(business_name, business_description, industry, primary_keywords)
+
+# Return all extensions
+return {
+"sitelinks": sitelinks,
+"callouts": callouts,
+"structured_snippets": snippets
+}
+
+def generate_sitelinks(business_name: str, business_description: str, industry: str,
+primary_keywords: List[str], landing_page: str) -> List[Dict]:
+"""
+Generate sitelink extensions based on business information.
+
+Args:
+business_name: Name of the business
+business_description: Description of the business
+industry: Industry of the business
+primary_keywords: List of primary keywords
+landing_page: Landing page URL
+
+Returns:
+List of dictionaries with sitelink information
+"""
+# Define common sitelink types by industry
+industry_sitelinks = {
+"E-commerce": ["Shop Now", "Best Sellers", "New Arrivals", "Sale Items", "Customer Reviews", "About Us"],
+"SaaS/Technology": ["Features", "Pricing", "Demo", "Case Studies", "Support", "Blog"],
+"Healthcare": ["Services", "Locations", "Providers", "Insurance", "Patient Portal", "Contact Us"],
+"Education": ["Programs", "Admissions", "Campus", "Faculty", "Student Life", "Apply Now"],
+"Finance": ["Services", "Rates", "Calculators", "Locations", "Apply Now", "About Us"],
+"Real Estate": ["Listings", "Sell Your Home", "Neighborhoods", "Agents", "Mortgage", "Contact Us"],
+"Legal": ["Practice Areas", "Attorneys", "Results", "Testimonials", "Free Consultation", "Contact"],
+"Travel": ["Destinations", "Deals", "Book Now", "Reviews", "FAQ", "Contact Us"],
+"Food & Beverage": ["Menu", "Locations", "Order Online", "Reservations", "Catering", "About Us"]
+}
+
+# Get sitelinks for the specified industry, or use default
+sitelink_types = industry_sitelinks.get(industry, ["About Us", "Services", "Products", "Contact Us", "Testimonials", "FAQ"])
+
+# Generate sitelinks
+sitelinks = []
+base_url = landing_page.rstrip('/') if landing_page else ""
+
+for sitelink_type in sitelink_types:
+# Generate URL path based on sitelink type
+path = sitelink_type.lower().replace(' ', '-')
+url = f"{base_url}/{path}" if base_url else f"https://example.com/{path}"
+
+# Generate description based on sitelink type
+description = ""
+if sitelink_type == "About Us":
+description = f"Learn more about {business_name} and our mission."
+elif sitelink_type == "Services" or sitelink_type == "Products":
+description = f"Explore our range of {primary_keywords[0] if primary_keywords else 'offerings'}."
+elif sitelink_type == "Contact Us":
+description = f"Get in touch with our team for assistance."
+elif sitelink_type == "Testimonials" or sitelink_type == "Reviews":
+description = f"See what our customers say about us."
+elif sitelink_type == "FAQ":
+description = f"Find answers to common questions."
+elif sitelink_type == "Pricing" or sitelink_type == "Rates":
+description = f"View our competitive pricing options."
+elif sitelink_type == "Shop Now" or sitelink_type == "Order Online":
+description = f"Browse and purchase our {primary_keywords[0] if primary_keywords else 'products'} online."
+
+# Add the sitelink
+sitelinks.append({
+"text": sitelink_type,
+"url": url,
+"description": description
+})
+
+return sitelinks
+
+def generate_callouts(business_name: str, unique_selling_points: List[str], industry: str) -> List[str]:
+"""
+Generate callout extensions based on business information.
+
+Args:
+business_name: Name of the business
+unique_selling_points: List of unique selling points
+industry: Industry of the business
+
+Returns:
+List of callout texts
+"""
+# Use provided USPs if available
+if unique_selling_points and len(unique_selling_points) >= 4:
+# Ensure callouts are not too long (25 characters max)
+callouts = []
+for usp in unique_selling_points:
+if len(usp) <= 25:
+callouts.append(usp)
+else:
+# Try to truncate at a space
+truncated = usp[:22] + "..."
+callouts.append(truncated)
+
+return callouts[:8] # Return up to 8 callouts
+
+# Define common callouts by industry
+industry_callouts = {
+"E-commerce": ["Free Shipping", "24/7 Customer Service", "Secure Checkout", "Easy Returns", "Price Match Guarantee", "Next Day Delivery", "Satisfaction Guaranteed", "Exclusive Deals"],
+"SaaS/Technology": ["24/7 Support", "Free Trial", "No Credit Card Required", "Easy Integration", "Data Security", "Cloud-Based", "Regular Updates", "Customizable"],
+"Healthcare": ["Board Certified", "Most Insurance Accepted", "Same-Day Appointments", "Compassionate Care", "State-of-the-Art Facility", "Experienced Staff", "Convenient Location", "Telehealth Available"],
+"Education": ["Accredited Programs", "Expert Faculty", "Financial Aid", "Career Services", "Small Class Sizes", "Flexible Schedule", "Online Options", "Hands-On Learning"],
+"Finance": ["FDIC Insured", "No Hidden Fees", "Personalized Service", "Online Banking", "Mobile App", "Low Interest Rates", "Financial Planning", "Retirement Services"],
+"Real Estate": ["Free Home Valuation", "Virtual Tours", "Experienced Agents", "Local Expertise", "Financing Available", "Property Management", "Commercial & Residential", "Investment Properties"],
+"Legal": ["Free Consultation", "No Win No Fee", "Experienced Attorneys", "24/7 Availability", "Proven Results", "Personalized Service", "Multiple Practice Areas", "Aggressive Representation"]
+}
+
+# Get callouts for the specified industry, or use default
+callouts = industry_callouts.get(industry, ["Professional Service", "Experienced Team", "Customer Satisfaction", "Quality Guaranteed", "Competitive Pricing", "Fast Service", "Personalized Solutions", "Trusted Provider"])
+
+return callouts
+
+def generate_structured_snippets(business_name: str, business_description: str, industry: str, primary_keywords: List[str]) -> Dict:
+"""
+Generate structured snippet extensions based on business information.
+
+Args:
+business_name: Name of the business
+business_description: Description of the business
+industry: Industry of the business
+primary_keywords: List of primary keywords
+
+Returns:
+Dictionary with structured snippet information
+"""
+# Define common snippet headers and values by industry
+industry_snippets = {
+"E-commerce": {
+"header": "Brands",
+"values": ["Nike", "Adidas", "Apple", "Samsung", "Sony", "LG", "Dell", "HP"]
+},
+"SaaS/Technology": {
+"header": "Services",
+"values": ["Cloud Storage", "Data Analytics", "CRM", "Project Management", "Email Marketing", "Cybersecurity", "API Integration", "Automation"]
+},
+"Healthcare": {
+"header": "Services",
+"values": ["Preventive Care", "Diagnostics", "Treatment", "Surgery", "Rehabilitation", "Counseling", "Telemedicine", "Wellness Programs"]
+},
+"Education": {
+"header": "Courses",
+"values": ["Business", "Technology", "Healthcare", "Design", "Engineering", "Education", "Arts", "Sciences"]
+},
+"Finance": {
+"header": "Services",
+"values": ["Checking Accounts", "Savings Accounts", "Loans", "Mortgages", "Investments", "Retirement Planning", "Insurance", "Wealth Management"]
+},
+"Real Estate": {
+"header": "Types",
+"values": ["Single-Family Homes", "Condos", "Townhouses", "Apartments", "Commercial", "Land", "New Construction", "Luxury Homes"]
+},
+"Legal": {
+"header": "Services",
+"values": ["Personal Injury", "Family Law", "Criminal Defense", "Estate Planning", "Business Law", "Immigration", "Real Estate Law", "Intellectual Property"]
+}
+}
+
+# Get snippets for the specified industry, or use default
+snippet_info = industry_snippets.get(industry, {
+"header": "Services",
+"values": ["Consultation", "Assessment", "Implementation", "Support", "Maintenance", "Training", "Customization", "Analysis"]
+})
+
+# If we have primary keywords, try to incorporate them
+if primary_keywords:
+# Try to determine a better header based on keywords
+service_keywords = ["service", "support", "consultation", "assistance", "help"]
+product_keywords = ["product", "item", "good", "merchandise"]
+brand_keywords = ["brand", "make", "manufacturer"]
+
+for kw in primary_keywords:
+kw_lower = kw.lower()
+if any(service_word in kw_lower for service_word in service_keywords):
+snippet_info["header"] = "Services"
+break
+elif any(product_word in kw_lower for product_word in product_keywords):
+snippet_info["header"] = "Products"
+break
+elif any(brand_word in kw_lower for brand_word in brand_keywords):
+snippet_info["header"] = "Brands"
+break
+
+return snippet_info
+
+def generate_custom_extensions(business_info: Dict, extension_type: str) -> Any:
+"""
+Generate custom extensions using AI based on business information.
+
+Args:
+business_info: Dictionary with business information
+extension_type: Type of extension to generate
+
+Returns:
+Generated extension data
+"""
+# Extract business information
+business_name = business_info.get("business_name", "")
+business_description = business_info.get("business_description", "")
+industry = business_info.get("industry", "")
+primary_keywords = business_info.get("primary_keywords", [])
+unique_selling_points = business_info.get("unique_selling_points", [])
+
+# Create a prompt based on extension type
+if extension_type == "sitelinks":
+prompt = f"""
+Generate 6 sitelink extensions for a Google Ads campaign for the following business:
+
+Business Name: {business_name}
+Business Description: {business_description}
+Industry: {industry}
+Keywords: {', '.join(primary_keywords)}
+
+For each sitelink, provide:
+1. Link text (max 25 characters)
+2. Description line 1 (max 35 characters)
+3. Description line 2 (max 35 characters)
+
+Format the response as a JSON array of objects with "text", "description1", and "description2" fields.
+"""
+elif extension_type == "callouts":
+prompt = f"""
+Generate 8 callout extensions for a Google Ads campaign for the following business:
+
+Business Name: {business_name}
+Business Description: {business_description}
+Industry: {industry}
+Keywords: {', '.join(primary_keywords)}
+Unique Selling Points: {', '.join(unique_selling_points)}
+
+Each callout should:
+1. Be 25 characters or less
+2. Highlight a feature, benefit, or unique selling point
+3. Be concise and impactful
+
+Format the response as a JSON array of strings.
+"""
+elif extension_type == "structured_snippets":
+prompt = f"""
+Generate structured snippet extensions for a Google Ads campaign for the following business:
+
+Business Name: {business_name}
+Business Description: {business_description}
+Industry: {industry}
+Keywords: {', '.join(primary_keywords)}
+
+Provide:
+1. The most appropriate header type (e.g., Brands, Services, Products, Courses, etc.)
+2. 8 values that are relevant to the business (each 25 characters or less)
+
+Format the response as a JSON object with "header" and "values" fields.
+"""
+else:
+return None
+
+# Generate the extensions using the LLM
+try:
+response = llm_text_gen(prompt)
+
+# Process the response based on extension type
+# In a real implementation, you would parse the JSON response
+# For this example, we'll return a placeholder
+
+if extension_type == "sitelinks":
+return [
+{"text": "About Us", "description1": "Learn about our company", "description2": "Our history and mission"},
+{"text": "Services", "description1": "Explore our service offerings", "description2": "Solutions for your needs"},
+{"text": "Products", "description1": "Browse our product catalog", "description2": "Quality items at great prices"},
+{"text": "Contact Us", "description1": "Get in touch with our team", "description2": "We're here to help you"},
+{"text": "Testimonials", "description1": "See what customers say", "description2": "Real reviews from real people"},
+{"text": "FAQ", "description1": "Frequently asked questions", "description2": "Find quick answers here"}
+]
+elif extension_type == "callouts":
+return ["Free Shipping", "24/7 Support", "Money-Back Guarantee", "Expert Team", "Premium Quality", "Fast Service", "Affordable Prices", "Satisfaction Guaranteed"]
+elif extension_type == "structured_snippets":
+return {"header": "Services", "values": ["Consultation", "Installation", "Maintenance", "Repair", "Training", "Support", "Design", "Analysis"]}
+else:
+return None
+
+except Exception as e:
+print(f"Error generating extensions: {str(e)}")
+return None
\ No newline at end of file
diff --git a/lib/ai_marketing_tools/ai_google_ads_generator/ad_templates.py b/lib/ai_marketing_tools/ai_google_ads_generator/ad_templates.py
new file mode 100644
index 00000000..0e701fcf
--- /dev/null
+++ b/lib/ai_marketing_tools/ai_google_ads_generator/ad_templates.py
@@ -0,0 +1,219 @@
+"""
+Ad Templates Module
+
+This module provides templates for different ad types and industries.
+"""
+
+from typing import Dict, List, Any
+
+def get_industry_templates(industry: str) -> Dict:
+"""
+Get ad templates specific to an industry.
+
+Args:
+industry: The industry to get templates for
+
+Returns:
+Dictionary with industry-specific templates
+"""
+# Define templates for different industries
+templates = {
+"E-commerce": {
+"headline_templates": [
+"{product} - {benefit} | {business_name}",
+"Shop {product} - {discount} Off Today",
+"Top-Rated {product} - Free Shipping",
+"{benefit} with Our {product}",
+"New {product} Collection - {benefit}",
+"{discount}% Off {product} - Limited Time",
+"Buy {product} Online - Fast Delivery",
+"{product} Sale Ends {timeframe}",
+"Best-Selling {product} from {business_name}",
+"Premium {product} - {benefit}"
+],
+"description_templates": [
+"Shop our selection of {product} and enjoy {benefit}. Free shipping on orders over ${amount}. Order now!",
+"Looking for quality {product}? Get {benefit} with our {product}. {discount} off your first order!",
+"{business_name} offers premium {product} with {benefit}. Shop online or visit our store today!",
+"Discover our {product} collection. {benefit} guaranteed or your money back. Order now and save {discount}!"
+],
+"emotional_triggers": ["exclusive", "limited time", "sale", "discount", "free shipping", "bestseller", "new arrival"],
+"call_to_actions": ["Shop Now", "Buy Today", "Order Online", "Get Yours", "Add to Cart", "Save Today"]
+},
+"SaaS/Technology": {
+"headline_templates": [
+"{product} Software - {benefit}",
+"Try {product} Free for {timeframe}",
+"{benefit} with Our {product} Platform",
+"{product} - Rated #1 for {feature}",
+"New {feature} in Our {product} Software",
+"{business_name} - {benefit} Software",
+"Streamline {pain_point} with {product}",
+"{product} Software - {discount} Off",
+"Enterprise-Grade {product} for {audience}",
+"{product} - {benefit} Guaranteed"
+],
+"description_templates": [
+"{business_name}'s {product} helps you {benefit}. Try it free for {timeframe}. No credit card required.",
+"Struggling with {pain_point}? Our {product} provides {benefit}. Join {number}+ satisfied customers.",
+"Our {product} platform offers {feature} to help you {benefit}. Rated {rating}/5 by {source}.",
+"{product} by {business_name}: {benefit} for your business. Plans starting at ${price}/month."
+],
+"emotional_triggers": ["efficient", "time-saving", "seamless", "integrated", "secure", "scalable", "innovative"],
+"call_to_actions": ["Start Free Trial", "Request Demo", "Learn More", "Sign Up Free", "Get Started", "See Plans"]
+},
+"Healthcare": {
+"headline_templates": [
+"{service} in {location} | {business_name}",
+"Expert {service} - {benefit}",
+"Quality {service} for {audience}",
+"{business_name} - {credential} {professionals}",
+"Same-Day {service} Appointments",
+"{service} Specialists in {location}",
+"Affordable {service} - {benefit}",
+"{symptom}? Get {service} Today",
+"Advanced {service} Technology",
+"Compassionate {service} Care"
+],
+"description_templates": [
+"{business_name} provides expert {service} with {benefit}. Our {credential} team is ready to help. Schedule today!",
+"Experiencing {symptom}? Our {professionals} offer {service} with {benefit}. Most insurance accepted.",
+"Quality {service} in {location}. {benefit} from our experienced team. Call now to schedule your appointment.",
+"Our {service} center provides {benefit} for {audience}. Open {days} with convenient hours."
+],
+"emotional_triggers": ["trusted", "experienced", "compassionate", "advanced", "personalized", "comprehensive", "gentle"],
+"call_to_actions": ["Schedule Now", "Book Appointment", "Call Today", "Free Consultation", "Learn More", "Find Relief"]
+},
+"Real Estate": {
+"headline_templates": [
+"{property_type} in {location} | {business_name}",
+"{property_type} for {price_range} - {location}",
+"Find Your Dream {property_type} in {location}",
+"{feature} {property_type} - {location}",
+"New {property_type} Listings in {location}",
+"Sell Your {property_type} in {timeframe}",
+"{business_name} - {credential} {professionals}",
+"{property_type} {benefit} - {location}",
+"Exclusive {property_type} Listings",
+"{number}+ {property_type} Available Now"
+],
+"description_templates": [
+"Looking for {property_type} in {location}? {business_name} offers {benefit}. Browse our listings or call us today!",
+"Sell your {property_type} in {location} with {business_name}. Our {professionals} provide {benefit}. Free valuation!",
+"{business_name}: {credential} {professionals} helping you find the perfect {property_type} in {location}. Call now!",
+"Discover {feature} {property_type} in {location}. Prices from {price_range}. Schedule a viewing today!"
+],
+"emotional_triggers": ["dream home", "exclusive", "luxury", "investment", "perfect location", "spacious", "modern"],
+"call_to_actions": ["View Listings", "Schedule Viewing", "Free Valuation", "Call Now", "Learn More", "Get Pre-Approved"]
+}
+}
+
+# Return templates for the specified industry, or a default if not found
+return templates.get(industry, {
+"headline_templates": [
+"{product/service} - {benefit} | {business_name}",
+"Professional {product/service} - {benefit}",
+"{benefit} with Our {product/service}",
+"{business_name} - {credential} {product/service}",
+"Quality {product/service} for {audience}",
+"Affordable {product/service} - {benefit}",
+"{product/service} in {location}",
+"{feature} {product/service} by {business_name}",
+"Experienced {product/service} Provider",
+"{product/service} - Satisfaction Guaranteed"
+],
+"description_templates": [
+"{business_name} offers professional {product/service} with {benefit}. Contact us today to learn more!",
+"Looking for quality {product/service}? {business_name} provides {benefit}. Call now for more information.",
+"Our {product/service} helps you {benefit}. Trusted by {number}+ customers. Contact us today!",
+"{business_name}: {credential} {product/service} provider. We offer {benefit} for {audience}. Learn more!"
+],
+"emotional_triggers": ["professional", "quality", "trusted", "experienced", "affordable", "reliable", "satisfaction"],
+"call_to_actions": ["Contact Us", "Learn More", "Call Now", "Get Quote", "Visit Website", "Schedule Consultation"]
+})
+
+def get_ad_type_templates(ad_type: str) -> Dict:
+"""
+Get templates specific to an ad type.
+
+Args:
+ad_type: The ad type to get templates for
+
+Returns:
+Dictionary with ad type-specific templates
+"""
+# Define templates for different ad types
+templates = {
+"Responsive Search Ad": {
+"headline_count": 15,
+"description_count": 4,
+"headline_max_length": 30,
+"description_max_length": 90,
+"best_practices": [
+"Include at least 3 headlines with keywords",
+"Create headlines with different lengths",
+"Include at least 1 headline with a call to action",
+"Include at least 1 headline with your brand name",
+"Create descriptions that complement each other",
+"Include keywords in at least 2 descriptions",
+"Include a call to action in at least 1 description"
+]
+},
+"Expanded Text Ad": {
+"headline_count": 3,
+"description_count": 2,
+"headline_max_length": 30,
+"description_max_length": 90,
+"best_practices": [
+"Include keywords in Headline 1",
+"Use a call to action in Headline 2 or 3",
+"Include your brand name in one headline",
+"Make descriptions complementary but able to stand alone",
+"Include keywords in at least one description",
+"Include a call to action in at least one description"
+]
+},
+"Call-Only Ad": {
+"headline_count": 2,
+"description_count": 2,
+"headline_max_length": 30,
+"description_max_length": 90,
+"best_practices": [
+"Focus on encouraging phone calls",
+"Include language like 'Call now', 'Speak to an expert', etc.",
+"Mention phone availability (e.g., '24/7', 'Available now')",
+"Include benefits of calling rather than clicking",
+"Be clear about who will answer the call",
+"Include any special offers for callers"
+]
+},
+"Dynamic Search Ad": {
+"headline_count": 0, # Headlines are dynamically generated
+"description_count": 2,
+"headline_max_length": 0, # N/A
+"description_max_length": 90,
+"best_practices": [
+"Create descriptions that work with any dynamically generated headline",
+"Focus on your unique selling points",
+"Include a strong call to action",
+"Highlight benefits that apply across your product/service range",
+"Avoid specific product mentions that might not match the dynamic headline"
+]
+}
+}
+
+# Return templates for the specified ad type, or a default if not found
+return templates.get(ad_type, {
+"headline_count": 3,
+"description_count": 2,
+"headline_max_length": 30,
+"description_max_length": 90,
+"best_practices": [
+"Include keywords in headlines",
+"Use a call to action",
+"Include your brand name",
+"Make descriptions informative and compelling",
+"Include keywords in descriptions",
+"Highlight unique selling points"
+]
+})
\ No newline at end of file
diff --git a/lib/ai_marketing_tools/ai_google_ads_generator/google_ads_generator.py b/lib/ai_marketing_tools/ai_google_ads_generator/google_ads_generator.py
new file mode 100644
index 00000000..4d408d55
--- /dev/null
+++ b/lib/ai_marketing_tools/ai_google_ads_generator/google_ads_generator.py
@@ -0,0 +1,1346 @@
+"""
+Google Ads Generator Module
+
+This module provides a comprehensive UI for generating high-converting Google Ads
+based on user inputs and best practices.
+"""
+
+import streamlit as st
+import pandas as pd
+import time
+import json
+from datetime import datetime
+import re
+import random
+from typing import Dict, List, Tuple, Any, Optional
+
+# Import internal modules
+from ...gpt_providers.text_generation.main_text_generation import llm_text_gen
+from .ad_analyzer import analyze_ad_quality, calculate_quality_score, analyze_keyword_relevance
+from .ad_templates import get_industry_templates, get_ad_type_templates
+from .ad_extensions_generator import generate_extensions
+
+def write_google_ads():
+"""Main function to render the Google Ads Generator UI."""
+
+# Page title and description
+st.title("🚀 AI Google Ads Generator")
+st.markdown("""
+Create high-converting Google Ads that drive clicks and conversions.
+Our AI-powered tool follows Google Ads best practices to help you maximize your ad spend ROI.
+""")
+
+# Initialize session state for storing generated ads
+if "generated_ads" not in st.session_state:
+st.session_state.generated_ads = []
+
+if "selected_ad_index" not in st.session_state:
+st.session_state.selected_ad_index = None
+
+if "ad_history" not in st.session_state:
+st.session_state.ad_history = []
+
+# Create tabs for different sections
+tabs = st.tabs(["Ad Creation", "Ad Performance", "Ad History", "Best Practices"])
+
+with tabs[0]:
+render_ad_creation_tab()
+
+with tabs[1]:
+render_ad_performance_tab()
+
+with tabs[2]:
+render_ad_history_tab()
+
+with tabs[3]:
+render_best_practices_tab()
+
+def render_ad_creation_tab():
+"""Render the Ad Creation tab with all input fields."""
+
+# Create columns for a better layout
+col1, col2 = st.columns([2, 1])
+
+with col1:
+st.subheader("Campaign Details")
+
+# Business information
+business_name = st.text_input(
+"Business Name",
+help="Enter your business or brand name"
+)
+
+business_description = st.text_area(
+"Business Description",
+help="Briefly describe your business, products, or services (100-200 characters recommended)",
+max_chars=500
+)
+
+# Industry selection
+industries = [
+"E-commerce", "SaaS/Technology", "Healthcare", "Education",
+"Finance", "Real Estate", "Legal", "Travel", "Food & Beverage",
+"Fashion", "Beauty", "Fitness", "Home Services", "B2B Services",
+"Entertainment", "Automotive", "Non-profit", "Other"
+]
+
+industry = st.selectbox(
+"Industry",
+industries,
+help="Select the industry that best matches your business"
+)
+
+# Campaign objective
+objectives = [
+"Sales", "Leads", "Website Traffic", "Brand Awareness",
+"App Promotion", "Local Store Visits", "Product Consideration"
+]
+
+campaign_objective = st.selectbox(
+"Campaign Objective",
+objectives,
+help="What is the main goal of your advertising campaign?"
+)
+
+# Target audience
+target_audience = st.text_area(
+"Target Audience",
+help="Describe your ideal customer (age, interests, pain points, etc.)",
+max_chars=300
+)
+
+# Create a container for the keyword section
+keyword_container = st.container()
+
+with keyword_container:
+st.subheader("Keywords & Targeting")
+
+# Primary keywords
+primary_keywords = st.text_area(
+"Primary Keywords (1 per line)",
+help="Enter your main keywords (1-5 recommended). These will be prominently featured in your ads.",
+height=100
+)
+
+# Secondary keywords
+secondary_keywords = st.text_area(
+"Secondary Keywords (1 per line)",
+help="Enter additional relevant keywords that can be included when appropriate.",
+height=100
+)
+
+# Negative keywords
+negative_keywords = st.text_area(
+"Negative Keywords (1 per line)",
+help="Enter terms you want to avoid in your ads.",
+height=100
+)
+
+# Match type selection
+match_types = st.multiselect(
+"Keyword Match Types",
+["Broad Match", "Phrase Match", "Exact Match"],
+default=["Phrase Match"],
+help="Select the match types you want to use for your keywords"
+)
+
+with col2:
+st.subheader("Ad Specifications")
+
+# Ad type
+ad_types = [
+"Responsive Search Ad",
+"Expanded Text Ad",
+"Call-Only Ad",
+"Dynamic Search Ad"
+]
+
+ad_type = st.selectbox(
+"Ad Type",
+ad_types,
+help="Select the type of Google Ad you want to create"
+)
+
+# Number of ad variations
+num_variations = st.slider(
+"Number of Ad Variations",
+min_value=1,
+max_value=5,
+value=3,
+help="Generate multiple ad variations for A/B testing"
+)
+
+# Unique selling points
+usp = st.text_area(
+"Unique Selling Points (1 per line)",
+help="What makes your product/service unique? (e.g., Free shipping, 24/7 support)",
+height=100
+)
+
+# Call to action
+cta_options = [
+"Shop Now", "Learn More", "Sign Up", "Get Started",
+"Contact Us", "Book Now", "Download", "Request a Demo",
+"Get a Quote", "Subscribe", "Join Now", "Apply Now",
+"Custom"
+]
+
+cta_selection = st.selectbox(
+"Call to Action",
+cta_options,
+help="Select a primary call to action for your ads"
+)
+
+if cta_selection == "Custom":
+custom_cta = st.text_input(
+"Custom Call to Action",
+help="Enter your custom call to action (keep it short and action-oriented)"
+)
+
+# Landing page URL
+landing_page = st.text_input(
+"Landing Page URL",
+help="Enter the URL where users will be directed after clicking your ad"
+)
+
+# Ad tone
+tone_options = [
+"Professional", "Conversational", "Urgent", "Informative",
+"Persuasive", "Empathetic", "Authoritative", "Friendly"
+]
+
+ad_tone = st.selectbox(
+"Ad Tone",
+tone_options,
+help="Select the tone of voice for your ads"
+)
+
+# Ad Extensions section
+st.subheader("Ad Extensions")
+st.markdown("Ad extensions improve visibility and provide additional information to potential customers.")
+
+# Create columns for extension types
+ext_col1, ext_col2 = st.columns(2)
+
+with ext_col1:
+# Sitelink extensions
+st.markdown("##### Sitelink Extensions")
+num_sitelinks = st.slider("Number of Sitelinks", 0, 6, 4)
+
+sitelinks = []
+if num_sitelinks > 0:
+for i in range(num_sitelinks):
+col1, col2 = st.columns(2)
+with col1:
+link_text = st.text_input(f"Sitelink {i+1} Text", key=f"sitelink_text_{i}")
+with col2:
+link_url = st.text_input(f"Sitelink {i+1} URL", key=f"sitelink_url_{i}")
+
+link_desc = st.text_input(
+f"Sitelink {i+1} Description (optional)",
+key=f"sitelink_desc_{i}",
+help="Optional: Add 1-2 description lines (max 35 chars each)"
+)
+
+if link_text and link_url:
+sitelinks.append({
+"text": link_text,
+"url": link_url,
+"description": link_desc
+})
+
+# Callout extensions
+st.markdown("##### Callout Extensions")
+callout_text = st.text_area(
+"Callout Extensions (1 per line)",
+help="Add short phrases highlighting your business features (e.g., '24/7 Customer Service')",
+height=100
+)
+
+with ext_col2:
+# Structured snippet extensions
+st.markdown("##### Structured Snippet Extensions")
+snippet_headers = [
+"Brands", "Courses", "Degree Programs", "Destinations",
+"Featured Hotels", "Insurance Coverage", "Models",
+"Neighborhoods", "Service Catalog", "Services",
+"Shows", "Styles", "Types"
+]
+
+snippet_header = st.selectbox("Snippet Header", snippet_header_options)
+snippet_values = st.text_area(
+"Snippet Values (1 per line)",
+help="Add values related to the selected header (e.g., for 'Services': 'Cleaning', 'Repairs')",
+height=100
+)
+
+# Call extensions
+st.markdown("##### Call Extension")
+include_call = st.checkbox("Include Call Extension")
+if include_call:
+phone_number = st.text_input("Phone Number")
+
+# Advanced options in an expander
+with st.expander("Advanced Options"):
+col1, col2 = st.columns(2)
+
+with col1:
+# Device preference
+device_preference = st.multiselect(
+"Device Preference",
+["Mobile", "Desktop", "Tablet"],
+default=["Mobile", "Desktop"],
+help="Select which devices to optimize ads for"
+)
+
+# Location targeting
+location_targeting = st.text_input(
+"Location Targeting",
+help="Enter locations to target (e.g., 'New York, Los Angeles')"
+)
+
+with col2:
+# Competitor analysis
+competitor_urls = st.text_area(
+"Competitor URLs (1 per line)",
+help="Enter URLs of competitors for analysis (optional)",
+height=100
+)
+
+# Budget information
+daily_budget = st.number_input(
+"Daily Budget ($)",
+min_value=1.0,
+value=50.0,
+help="Enter your daily budget for this campaign"
+)
+
+# Generate button
+if st.button("Generate Google Ads", type="primary"):
+if not business_name or not business_description or not primary_keywords:
+st.error("Please fill in the required fields: Business Name, Business Description, and Primary Keywords.")
+return
+
+with st.spinner("Generating high-converting Google Ads..."):
+# Process keywords
+primary_kw_list = [kw.strip() for kw in primary_keywords.split("\n") if kw.strip()]
+secondary_kw_list = [kw.strip() for kw in secondary_keywords.split("\n") if kw.strip()]
+negative_kw_list = [kw.strip() for kw in negative_keywords.split("\n") if kw.strip()]
+
+# Process USPs
+usp_list = [point.strip() for point in usp.split("\n") if point.strip()]
+
+# Process callouts
+callout_list = [callout.strip() for callout in callout_text.split("\n") if callout.strip()]
+
+# Process snippets
+snippet_list = [snippet.strip() for snippet in snippet_values.split("\n") if snippet.strip()]
+
+# Get the CTA
+final_cta = custom_cta if cta_selection == "Custom" else cta_selection
+
+# Generate ads
+generated_ads = generate_google_ads(
+business_name=business_name,
+business_description=business_description,
+industry=industry,
+campaign_objective=campaign_objective,
+target_audience=target_audience,
+primary_keywords=primary_kw_list,
+secondary_keywords=secondary_kw_list,
+negative_keywords=negative_kw_list,
+match_types=match_types,
+ad_type=ad_type,
+num_variations=num_variations,
+unique_selling_points=usp_list,
+call_to_action=final_cta,
+landing_page=landing_page,
+ad_tone=ad_tone,
+sitelinks=sitelinks,
+callouts=callout_list,
+snippet_header=snippet_header,
+snippet_values=snippet_list,
+phone_number=phone_number if include_call else None,
+device_preference=device_preference,
+location_targeting=location_targeting,
+competitor_urls=[url.strip() for url in competitor_urls.split("\n") if url.strip()],
+daily_budget=daily_budget
+)
+
+if generated_ads:
+# Store the generated ads in session state
+st.session_state.generated_ads = generated_ads
+
+# Add to history
+st.session_state.ad_history.append({
+"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
+"business_name": business_name,
+"industry": industry,
+"campaign_objective": campaign_objective,
+"ads": generated_ads
+})
+
+# Display the generated ads
+display_generated_ads(generated_ads)
+else:
+st.error("Failed to generate ads. Please try again with different inputs.")
+
+def generate_google_ads(**kwargs) -> List[Dict]:
+"""
+Generate Google Ads based on user inputs.
+
+Args:
+**kwargs: All the user inputs from the form
+
+Returns:
+List of dictionaries containing generated ads and their metadata
+"""
+# Extract key parameters
+business_name = kwargs.get("business_name", "")
+business_description = kwargs.get("business_description", "")
+industry = kwargs.get("industry", "")
+campaign_objective = kwargs.get("campaign_objective", "")
+target_audience = kwargs.get("target_audience", "")
+primary_keywords = kwargs.get("primary_keywords", [])
+secondary_keywords = kwargs.get("secondary_keywords", [])
+negative_keywords = kwargs.get("negative_keywords", [])
+ad_type = kwargs.get("ad_type", "Responsive Search Ad")
+num_variations = kwargs.get("num_variations", 3)
+unique_selling_points = kwargs.get("unique_selling_points", [])
+call_to_action = kwargs.get("call_to_action", "Learn More")
+landing_page = kwargs.get("landing_page", "")
+ad_tone = kwargs.get("ad_tone", "Professional")
+
+# Get templates based on industry and ad type
+industry_templates = get_industry_templates(industry)
+ad_type_templates = get_ad_type_templates(ad_type)
+
+# Prepare the prompt for the LLM
+system_prompt = """You are an expert Google Ads copywriter with years of experience creating high-converting ads.
+Your task is to create Google Ads that follow best practices, maximize Quality Score, and drive high CTR and conversion rates.
+
+For each ad, provide:
+1. Headlines (3-15 depending on ad type)
+2. Descriptions (2-4 depending on ad type)
+3. Display URL path (2 fields)
+4. A brief explanation of why this ad would be effective
+
+Format your response as valid JSON with the following structure for each ad:
+{
+"headlines": ["Headline 1", "Headline 2", ...],
+"descriptions": ["Description 1", "Description 2", ...],
+"path1": "path-one",
+"path2": "path-two",
+"explanation": "Brief explanation of the ad's strengths"
+}
+
+IMPORTANT GUIDELINES:
+- Include primary keywords in headlines and descriptions
+- Ensure headlines are 30 characters or less
+- Ensure descriptions are 90 characters or less
+- Include the call to action in at least one headline or description
+- Make the ad relevant to the search intent
+- Highlight unique selling points
+- Use emotional triggers appropriate for the industry
+- Ensure the ad is compliant with Google Ads policies
+- Create distinct variations that test different approaches
+"""
+
+prompt = f"""
+Create {num_variations} high-converting Google {ad_type}s for the following business:
+
+BUSINESS INFORMATION:
+Business Name: {business_name}
+Business Description: {business_description}
+Industry: {industry}
+Campaign Objective: {campaign_objective}
+Target Audience: {target_audience}
+Landing Page: {landing_page}
+
+KEYWORDS:
+Primary Keywords: {', '.join(primary_keywords)}
+Secondary Keywords: {', '.join(secondary_keywords)}
+Negative Keywords: {', '.join(negative_keywords)}
+
+UNIQUE SELLING POINTS:
+{', '.join(unique_selling_points)}
+
+SPECIFICATIONS:
+Ad Type: {ad_type}
+Call to Action: {call_to_action}
+Tone: {ad_tone}
+
+ADDITIONAL INSTRUCTIONS:
+- For Responsive Search Ads, create 10-15 headlines and 2-4 descriptions
+- For Expanded Text Ads, create 3 headlines and 2 descriptions
+- For Call-Only Ads, focus on encouraging calls
+- For Dynamic Search Ads, create compelling descriptions that work with dynamically generated headlines
+- Include at least one headline with the primary keyword
+- Include the call to action in at least one headline and one description
+- Ensure all headlines are 30 characters or less
+- Ensure all descriptions are 90 characters or less
+- Use the business name in at least one headline
+- Create distinct variations that test different approaches and angles
+- Format the response as a valid JSON array of ad objects
+
+Return ONLY the JSON array with no additional text or explanation.
+"""
+
+try:
+# Generate the ads using the LLM
+response = llm_text_gen(prompt, system_prompt=system_prompt)
+
+# Parse the JSON response
+try:
+# Try to parse the response as JSON
+ads_data = json.loads(response)
+
+# If the response is not a list, wrap it in a list
+if not isinstance(ads_data, list):
+ads_data = [ads_data]
+
+# Process each ad
+processed_ads = []
+for i, ad in enumerate(ads_data):
+# Analyze the ad quality
+quality_analysis = analyze_ad_quality(
+ad,
+primary_keywords,
+secondary_keywords,
+business_name,
+call_to_action
+)
+
+# Calculate quality score
+quality_score = calculate_quality_score(
+ad,
+primary_keywords,
+landing_page,
+ad_type
+)
+
+# Add metadata to the ad
+processed_ad = {
+"id": f"ad_{int(time.time())}_{i}",
+"type": ad_type,
+"headlines": ad.get("headlines", []),
+"descriptions": ad.get("descriptions", []),
+"path1": ad.get("path1", ""),
+"path2": ad.get("path2", ""),
+"final_url": landing_page,
+"business_name": business_name,
+"primary_keywords": primary_keywords,
+"quality_analysis": quality_analysis,
+"quality_score": quality_score,
+"explanation": ad.get("explanation", ""),
+"created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+}
+
+processed_ads.append(processed_ad)
+
+return processed_ads
+
+except json.JSONDecodeError:
+# If JSON parsing fails, try to extract structured data from the text
+st.warning("Failed to parse JSON response. Attempting to extract structured data from text.")
+
+# Implement fallback parsing logic here
+# This is a simplified example - you would need more robust parsing
+headlines_pattern = r"Headlines?:(.*?)Descriptions?:"
+descriptions_pattern = r"Descriptions?:(.*?)(?:Path|Display URL|$)"
+
+ads_data = []
+variations = re.split(r"Ad Variation \d+:|Ad \d+:", response)
+
+for variation in variations:
+if not variation.strip():
+continue
+
+headlines_match = re.search(headlines_pattern, variation, re.DOTALL)
+descriptions_match = re.search(descriptions_pattern, variation, re.DOTALL)
+
+if headlines_match and descriptions_match:
+headlines = [h.strip() for h in re.findall(r'"([^"]*)"', headlines_match.group(1))]
+descriptions = [d.strip() for d in re.findall(r'"([^"]*)"', descriptions_match.group(1))]
+
+if not headlines:
+headlines = [h.strip() for h in re.findall(r'- (.*)', headlines_match.group(1))]
+
+if not descriptions:
+descriptions = [d.strip() for d in re.findall(r'- (.*)', descriptions_match.group(1))]
+
+ads_data.append({
+"headlines": headlines,
+"descriptions": descriptions,
+"path1": f"{primary_keywords[0].lower().replace(' ', '-')}" if primary_keywords else "",
+"path2": "info",
+"explanation": "Generated from text response"
+})
+
+# Process each ad as before
+processed_ads = []
+for i, ad in enumerate(ads_data):
+quality_analysis = analyze_ad_quality(
+ad,
+primary_keywords,
+secondary_keywords,
+business_name,
+call_to_action
+)
+
+quality_score = calculate_quality_score(
+ad,
+primary_keywords,
+landing_page,
+ad_type
+)
+
+processed_ad = {
+"id": f"ad_{int(time.time())}_{i}",
+"type": ad_type,
+"headlines": ad.get("headlines", []),
+"descriptions": ad.get("descriptions", []),
+"path1": ad.get("path1", ""),
+"path2": ad.get("path2", ""),
+"final_url": landing_page,
+"business_name": business_name,
+"primary_keywords": primary_keywords,
+"quality_analysis": quality_analysis,
+"quality_score": quality_score,
+"explanation": ad.get("explanation", ""),
+"created_at": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
+}
+
+processed_ads.append(processed_ad)
+
+return processed_ads
+
+except Exception as e:
+st.error(f"Error generating ads: {str(e)}")
+return []
+
+def display_generated_ads(ads: List[Dict]):
+"""
+Display the generated ads in a user-friendly format.
+
+Args:
+ads: List of dictionaries containing generated ads and their metadata
+"""
+st.subheader("Generated Google Ads")
+st.write(f"Generated {len(ads)} ad variations. Click on each ad to see details.")
+
+# Create tabs for different views
+ad_tabs = st.tabs(["Preview", "Performance Analysis", "Export"])
+
+with ad_tabs[0]:
+# Display each ad in an expander
+for i, ad in enumerate(ads):
+ad_type = ad.get("type", "Google Ad")
+quality_score = ad.get("quality_score", {}).get("overall_score", 0)
+
+# Create a color based on quality score
+if quality_score >= 8:
+quality_color = "green"
+elif quality_score >= 6:
+quality_color = "orange"
+else:
+quality_color = "red"
+
+with st.expander(f"Ad Variation {i+1} - Quality Score: {quality_score}/10", expanded=(i==0)):
+# Create columns for preview and details
+col1, col2 = st.columns([3, 2])
+
+with col1:
+# Display ad preview
+st.markdown("### Ad Preview")
+
+# Display headlines
+for j, headline in enumerate(ad.get("headlines", [])[:3]): # Show first 3 headlines
+st.markdown(f"**{headline}**")
+
+# Display URL
+display_url = f"{ad.get('final_url', '').replace('https://', '').replace('http://', '').split('/')[0]}/{ad.get('path1', '')}/{ad.get('path2', '')}"
+st.markdown(f"{display_url}", unsafe_allow_html=True)
+
+# Display descriptions
+for description in ad.get("descriptions", []):
+st.markdown(f"{description}")
+
+# Display explanation
+if ad.get("explanation"):
+st.markdown("#### Why this ad works:")
+st.markdown(f"_{ad.get('explanation')}_")
+
+with col2:
+# Display quality analysis
+st.markdown("### Quality Analysis")
+
+quality_analysis = ad.get("quality_analysis", {})
+quality_score_details = ad.get("quality_score", {})
+
+# Display quality score
+st.markdown(f"**Overall Quality Score:** {quality_score}/10", unsafe_allow_html=True)
+
+# Display individual metrics
+metrics = [
+("Keyword Relevance", quality_score_details.get("keyword_relevance", 0)),
+("Ad Relevance", quality_score_details.get("ad_relevance", 0)),
+("CTA Effectiveness", quality_score_details.get("cta_effectiveness", 0)),
+("Landing Page Relevance", quality_score_details.get("landing_page_relevance", 0))
+]
+
+for metric_name, metric_score in metrics:
+if metric_score >= 8:
+metric_color = "green"
+elif metric_score >= 6:
+metric_color = "orange"
+else:
+metric_color = "red"
+
+st.markdown(f"**{metric_name}:** {metric_score}/10", unsafe_allow_html=True)
+
+# Display strengths and improvements
+if quality_analysis.get("strengths"):
+st.markdown("#### Strengths:")
+for strength in quality_analysis.get("strengths", []):
+st.markdown(f"✅ {strength}")
+
+if quality_analysis.get("improvements"):
+st.markdown("#### Improvement Opportunities:")
+for improvement in quality_analysis.get("improvements", []):
+st.markdown(f"🔍 {improvement}")
+
+# Add buttons for actions
+col1, col2, col3 = st.columns(3)
+
+with col1:
+if st.button("Select This Ad", key=f"select_ad_{i}"):
+st.session_state.selected_ad_index = i
+st.success(f"Ad Variation {i+1} selected!")
+
+with col2:
+if st.button("Edit This Ad", key=f"edit_ad_{i}"):
+# This would open an editing interface
+st.info("Ad editing feature coming soon!")
+
+with col3:
+if st.button("Generate Similar", key=f"similar_ad_{i}"):
+st.info("Similar ad generation feature coming soon!")
+
+with ad_tabs[1]:
+# Display performance analysis
+st.subheader("Ad Performance Analysis")
+
+# Create a DataFrame for comparison
+comparison_data = []
+for i, ad in enumerate(ads):
+quality_score = ad.get("quality_score", {})
+
+comparison_data.append({
+"Ad Variation": f"Ad {i+1}",
+"Overall Score": quality_score.get("overall_score", 0),
+"Keyword Relevance": quality_score.get("keyword_relevance", 0),
+"Ad Relevance": quality_score.get("ad_relevance", 0),
+"CTA Effectiveness": quality_score.get("cta_effectiveness", 0),
+"Landing Page Relevance": quality_score.get("landing_page_relevance", 0),
+"Est. CTR": f"{quality_score.get('estimated_ctr', 0):.2f}%",
+"Est. Conv. Rate": f"{quality_score.get('estimated_conversion_rate', 0):.2f}%"
+})
+
+# Create a DataFrame and display it
+df = pd.DataFrame(comparison_data)
+st.dataframe(df, use_container_width=True)
+
+# Display a bar chart comparing overall scores
+st.subheader("Quality Score Comparison")
+chart_data = pd.DataFrame({
+"Ad Variation": [f"Ad {i+1}" for i in range(len(ads))],
+"Overall Score": [ad.get("quality_score", {}).get("overall_score", 0) for ad in ads]
+})
+
+st.bar_chart(chart_data, x="Ad Variation", y="Overall Score", use_container_width=True)
+
+# Display keyword analysis
+st.subheader("Keyword Analysis")
+
+if ads and len(ads) > 0:
+# Get the primary keywords from the first ad
+primary_keywords = ads[0].get("primary_keywords", [])
+
+# Analyze keyword usage across all ads
+keyword_data = []
+for keyword in primary_keywords:
+keyword_data.append({
+"Keyword": keyword,
+"Headline Usage": sum(1 for ad in ads if any(keyword.lower() in headline.lower() for headline in ad.get("headlines", []))),
+"Description Usage": sum(1 for ad in ads if any(keyword.lower() in desc.lower() for desc in ad.get("descriptions", []))),
+"Path Usage": sum(1 for ad in ads if keyword.lower() in ad.get("path1", "").lower() or keyword.lower() in ad.get("path2", "").lower())
+})
+
+# Create a DataFrame and display it
+kw_df = pd.DataFrame(keyword_data)
+st.dataframe(kw_df, use_container_width=True)
+
+with ad_tabs[2]:
+# Export options
+st.subheader("Export Options")
+
+# Select export format
+export_format = st.selectbox(
+"Export Format",
+["CSV", "Excel", "Google Ads Editor CSV", "JSON"]
+)
+
+# Select which ads to export
+export_selection = st.radio(
+"Export Selection",
+["All Generated Ads", "Selected Ad Only", "Ads Above Quality Score Threshold"]
+)
+
+if export_selection == "Ads Above Quality Score Threshold":
+quality_threshold = st.slider("Minimum Quality Score", 1, 10, 7)
+
+# Export button
+if st.button("Export Ads", type="primary"):
+# Determine which ads to export
+if export_selection == "All Generated Ads":
+ads_to_export = ads
+elif export_selection == "Selected Ad Only":
+if st.session_state.selected_ad_index is not None:
+ads_to_export = [ads[st.session_state.selected_ad_index]]
+else:
+st.warning("Please select an ad first.")
+ads_to_export = []
+else: # Above threshold
+ads_to_export = [ad for ad in ads if ad.get("quality_score", {}).get("overall_score", 0) >= quality_threshold]
+
+if ads_to_export:
+# Prepare the export data based on format
+if export_format == "CSV" or export_format == "Google Ads Editor CSV":
+# Create CSV data
+if export_format == "CSV":
+# Simple CSV format
+export_data = []
+for ad in ads_to_export:
+export_data.append({
+"Ad Type": ad.get("type", ""),
+"Headlines": " | ".join(ad.get("headlines", [])),
+"Descriptions": " | ".join(ad.get("descriptions", [])),
+"Path 1": ad.get("path1", ""),
+"Path 2": ad.get("path2", ""),
+"Final URL": ad.get("final_url", ""),
+"Quality Score": ad.get("quality_score", {}).get("overall_score", 0)
+})
+else:
+# Google Ads Editor format
+export_data = []
+for ad in ads_to_export:
+base_row = {
+"Action": "Add",
+"Campaign": "", # User would fill this in
+"Ad Group": "", # User would fill this in
+"Status": "Enabled",
+"Final URL": ad.get("final_url", ""),
+"Path 1": ad.get("path1", ""),
+"Path 2": ad.get("path2", "")
+}
+
+# Add headlines and descriptions based on ad type
+if ad.get("type") == "Responsive Search Ad":
+for i, headline in enumerate(ad.get("headlines", []), 1):
+base_row[f"Headline {i}"] = headline
+
+for i, desc in enumerate(ad.get("descriptions", []), 1):
+base_row[f"Description {i}"] = desc
+else:
+# For other ad types
+for i, headline in enumerate(ad.get("headlines", [])[:3], 1):
+base_row[f"Headline {i}"] = headline
+
+for i, desc in enumerate(ad.get("descriptions", [])[:2], 1):
+base_row[f"Description {i}"] = desc
+
+export_data.append(base_row)
+
+# Convert to DataFrame and then to CSV
+df = pd.DataFrame(export_data)
+csv = df.to_csv(index=False)
+
+# Create a download button
+st.download_button(
+label="Download CSV",
+data=csv,
+file_name=f"google_ads_export_{int(time.time())}.csv",
+mime="text/csv"
+)
+
+elif export_format == "Excel":
+# Create Excel data
+export_data = []
+for ad in ads_to_export:
+export_data.append({
+"Ad Type": ad.get("type", ""),
+"Headlines": " | ".join(ad.get("headlines", [])),
+"Descriptions": " | ".join(ad.get("descriptions", [])),
+"Path 1": ad.get("path1", ""),
+"Path 2": ad.get("path2", ""),
+"Final URL": ad.get("final_url", ""),
+"Quality Score": ad.get("quality_score", {}).get("overall_score", 0)
+})
+
+# Convert to DataFrame and then to Excel
+df = pd.DataFrame(export_data)
+
+# Create a temporary Excel file
+excel_file = f"google_ads_export_{int(time.time())}.xlsx"
+df.to_excel(excel_file, index=False)
+
+# Read the file and create a download button
+with open(excel_file, "rb") as f:
+st.download_button(
+label="Download Excel",
+data=f,
+file_name=excel_file,
+mime="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
+)
+
+else: # JSON
+# Convert to JSON
+json_data = json.dumps(ads_to_export, indent=2)
+
+# Create a download button
+st.download_button(
+label="Download JSON",
+data=json_data,
+file_name=f"google_ads_export_{int(time.time())}.json",
+mime="application/json"
+)
+else:
+st.warning("No ads to export based on your selection.")
+
+def render_ad_performance_tab():
+"""Render the Ad Performance tab with analytics and insights."""
+
+st.subheader("Ad Performance Simulator")
+st.write("Simulate how your ads might perform based on industry benchmarks and our predictive model.")
+
+# Check if we have generated ads
+if not st.session_state.generated_ads:
+st.info("Generate ads first to see performance predictions.")
+return
+
+# Get the selected ad or the first one
+selected_index = st.session_state.selected_ad_index if st.session_state.selected_ad_index is not None else 0
+
+if selected_index >= len(st.session_state.generated_ads):
+selected_index = 0
+
+selected_ad = st.session_state.generated_ads[selected_index]
+
+# Display the selected ad
+st.markdown(f"### Selected Ad (Variation {selected_index + 1})")
+
+# Create columns for the ad preview
+col1, col2 = st.columns([3, 2])
+
+with col1:
+# Display headlines
+for headline in selected_ad.get("headlines", [])[:3]:
+st.markdown(f"**{headline}**")
+
+# Display URL
+display_url = f"{selected_ad.get('final_url', '').replace('https://', '').replace('http://', '').split('/')[0]}/{selected_ad.get('path1', '')}/{selected_ad.get('path2', '')}"
+st.markdown(f"{display_url}", unsafe_allow_html=True)
+
+# Display descriptions
+for description in selected_ad.get("descriptions", []):
+st.markdown(f"{description}")
+
+with col2:
+# Display quality score
+quality_score = selected_ad.get("quality_score", {}).get("overall_score", 0)
+
+# Create a color based on quality score
+if quality_score >= 8:
+quality_color = "green"
+elif quality_score >= 6:
+quality_color = "orange"
+else:
+quality_color = "red"
+
+st.markdown(f"**Quality Score:** {quality_score}/10", unsafe_allow_html=True)
+
+# Display estimated metrics
+est_ctr = selected_ad.get("quality_score", {}).get("estimated_ctr", 0)
+est_conv_rate = selected_ad.get("quality_score", {}).get("estimated_conversion_rate", 0)
+
+st.markdown(f"**Estimated CTR:** {est_ctr:.2f}%")
+st.markdown(f"**Estimated Conversion Rate:** {est_conv_rate:.2f}%")
+
+# Performance simulation
+st.subheader("Performance Simulation")
+
+# Create columns for inputs
+col1, col2, col3 = st.columns(3)
+
+with col1:
+daily_budget = st.number_input("Daily Budget ($)", min_value=1.0, value=50.0)
+cost_per_click = st.number_input("Average CPC ($)", min_value=0.1, value=1.5, step=0.1)
+
+with col2:
+avg_conversion_value = st.number_input("Avg. Conversion Value ($)", min_value=0.0, value=50.0)
+time_period = st.selectbox("Time Period", ["Day", "Week", "Month"])
+
+with col3:
+# Use the estimated CTR and conversion rate from the ad quality score
+ctr_override = st.number_input("CTR Override (%)", min_value=0.1, max_value=100.0, value=est_ctr, step=0.1)
+conv_rate_override = st.number_input("Conversion Rate Override (%)", min_value=0.01, max_value=100.0, value=est_conv_rate, step=0.01)
+
+# Calculate performance metrics
+if time_period == "Day":
+multiplier = 1
+elif time_period == "Week":
+multiplier = 7
+else: # Month
+multiplier = 30
+
+total_budget = daily_budget * multiplier
+clicks = total_budget / cost_per_click
+impressions = clicks * 100 / ctr_override
+conversions = clicks * conv_rate_override / 100
+conversion_value = conversions * avg_conversion_value
+roi = ((conversion_value - total_budget) / total_budget) * 100 if total_budget > 0 else 0
+
+# Display the results
+st.subheader(f"Projected {time_period} Performance")
+
+# Create columns for metrics
+col1, col2, col3, col4 = st.columns(4)
+
+with col1:
+st.metric("Impressions", f"{impressions:,.0f}")
+st.metric("Clicks", f"{clicks:,.0f}")
+
+with col2:
+st.metric("CTR", f"{ctr_override:.2f}%")
+st.metric("Cost", f"${total_budget:,.2f}")
+
+with col3:
+st.metric("Conversions", f"{conversions:,.2f}")
+st.metric("Conversion Rate", f"{conv_rate_override:.2f}%")
+
+with col4:
+st.metric("Conversion Value", f"${conversion_value:,.2f}")
+st.metric("ROI", f"{roi:,.2f}%")
+
+# Display a chart
+st.subheader("Performance Over Time")
+
+# Create data for the chart
+chart_data = pd.DataFrame({
+"Day": list(range(1, multiplier + 1)),
+"Clicks": [clicks / multiplier] * multiplier,
+"Conversions": [conversions / multiplier] * multiplier,
+"Cost": [daily_budget] * multiplier,
+"Value": [conversion_value / multiplier] * multiplier
+})
+
+# Add some random variation to make the chart more realistic
+for i in range(len(chart_data)):
+variation_factor = 0.9 + (random.random() * 0.2) # Between 0.9 and 1.1
+chart_data.loc[i, "Clicks"] *= variation_factor
+chart_data.loc[i, "Conversions"] *= variation_factor
+chart_data.loc[i, "Value"] *= variation_factor
+
+# Calculate cumulative metrics
+chart_data["Cumulative Clicks"] = chart_data["Clicks"].cumsum()
+chart_data["Cumulative Conversions"] = chart_data["Conversions"].cumsum()
+chart_data["Cumulative Cost"] = chart_data["Cost"].cumsum()
+chart_data["Cumulative Value"] = chart_data["Value"].cumsum()
+chart_data["Cumulative ROI"] = ((chart_data["Cumulative Value"] - chart_data["Cumulative Cost"]) / chart_data["Cumulative Cost"]) * 100
+
+# Display the chart
+st.line_chart(chart_data.set_index("Day")[["Cumulative Clicks", "Cumulative Conversions"]])
+
+# Display ROI chart
+st.subheader("ROI Over Time")
+st.line_chart(chart_data.set_index("Day")["Cumulative ROI"])
+
+# Optimization recommendations
+st.subheader("Optimization Recommendations")
+
+# Generate recommendations based on the ad and performance metrics
+recommendations = []
+
+# Check if CTR is low
+if ctr_override < 2.0:
+recommendations.append({
+"title": "Improve Click-Through Rate",
+"description": "Your estimated CTR is below average. Consider testing more compelling headlines and stronger calls to action.",
+"impact": "High"
+})
+
+# Check if conversion rate is low
+if conv_rate_override < 3.0:
+recommendations.append({
+"title": "Enhance Landing Page Experience",
+"description": "Your conversion rate could be improved. Ensure your landing page is relevant to your ad and provides a clear path to conversion.",
+"impact": "High"
+})
+
+# Check if ROI is low
+if roi < 100:
+recommendations.append({
+"title": "Optimize for Higher ROI",
+"description": "Your ROI is below target. Consider increasing your conversion value or reducing your cost per click.",
+"impact": "Medium"
+})
+
+# Check keyword usage
+quality_analysis = selected_ad.get("quality_analysis", {})
+if quality_analysis.get("improvements"):
+for improvement in quality_analysis.get("improvements"):
+if "keyword" in improvement.lower():
+recommendations.append({
+"title": "Improve Keyword Relevance",
+"description": improvement,
+"impact": "Medium"
+})
+
+# Add general recommendations
+recommendations.append({
+"title": "Test Multiple Ad Variations",
+"description": "Continue testing different ad variations to identify the best performing combination of headlines and descriptions.",
+"impact": "Medium"
+})
+
+recommendations.append({
+"title": "Add Ad Extensions",
+"description": "Enhance your ad with sitelinks, callouts, and structured snippets to increase visibility and provide additional information.",
+"impact": "Medium"
+})
+
+# Display recommendations
+for i, rec in enumerate(recommendations):
+with st.expander(f"{rec['title']} (Impact: {rec['impact']})", expanded=(i==0)):
+st.write(rec["description"])
+
+def render_ad_history_tab():
+"""Render the Ad History tab with previously generated ads."""
+
+st.subheader("Ad History")
+st.write("View and manage your previously generated ads.")
+
+# Check if we have any history
+if not st.session_state.ad_history:
+st.info("No ad history yet. Generate some ads to see them here.")
+return
+
+# Display the history in reverse chronological order
+for i, history_item in enumerate(reversed(st.session_state.ad_history)):
+with st.expander(f"{history_item['timestamp']} - {history_item['business_name']} ({history_item['industry']})", expanded=(i==0)):
+# Display basic info
+st.write(f"**Campaign Objective:** {history_item['campaign_objective']}")
+st.write(f"**Number of Ads:** {len(history_item['ads'])}")
+
+# Add a button to view the ads
+if st.button("View These Ads", key=f"view_history_{i}"):
+# Set the current ads to these historical ads
+st.session_state.generated_ads = history_item['ads']
+st.success("Loaded ads from history. Go to the Ad Creation tab to view them.")
+
+# Add a button to delete from history
+if st.button("Delete from History", key=f"delete_history_{i}"):
+# Remove this item from history
+index_to_remove = len(st.session_state.ad_history) - 1 - i
+if 0 <= index_to_remove < len(st.session_state.ad_history):
+st.session_state.ad_history.pop(index_to_remove)
+st.success("Removed from history.")
+st.rerun()
+
+def render_best_practices_tab():
+"""Render the Best Practices tab with Google Ads guidelines and tips."""
+
+st.subheader("Google Ads Best Practices")
+st.write("Follow these guidelines to create high-performing Google Ads campaigns.")
+
+# Create tabs for different best practice categories
+bp_tabs = st.tabs(["Ad Copy", "Keywords", "Landing Pages", "Quality Score", "Extensions"])
+
+with bp_tabs[0]:
+st.markdown("""
+### Ad Copy Best Practices
+
+#### Headlines
+- **Include Primary Keywords**: Place your main keyword in at least one headline
+- **Highlight Benefits**: Focus on what the user gains, not just features
+- **Use Numbers and Stats**: Specific numbers increase credibility and CTR
+- **Create Urgency**: Words like "now," "today," or "limited time" drive action
+- **Ask Questions**: Engage users with relevant questions
+- **Keep It Short**: Aim for 25-30 characters for better display across devices
+
+#### Descriptions
+- **Expand on Headlines**: Provide more details about your offer
+- **Include Secondary Keywords**: Incorporate additional relevant keywords
+- **Add Specific CTAs**: Tell users exactly what action to take
+- **Address Pain Points**: Show how you solve the user's problems
+- **Include Proof**: Mention testimonials, reviews, or guarantees
+- **Use All Available Space**: Aim for 85-90 characters per description
+
+#### Display Path
+- **Include Keywords**: Add relevant keywords to your display path
+- **Create Clarity**: Use paths that indicate where users will land
+- **Be Specific**: Use product categories or service types
+""")
+
+st.info("""
+**Pro Tip**: Create at least 5 headlines and 4 descriptions for Responsive Search Ads to give Google's algorithm more options to optimize performance.
+""")
+
+with bp_tabs[1]:
+st.markdown("""
+### Keyword Best Practices
+
+#### Keyword Selection
+- **Use Specific Keywords**: More specific keywords typically have higher conversion rates
+- **Include Long-Tail Keywords**: These often have less competition and lower CPCs
+- **Group by Intent**: Separate keywords by search intent (informational, commercial, transactional)
+- **Consider Competitor Keywords**: Include competitor brand terms if your budget allows
+- **Use Location Keywords**: Add location-specific terms for local businesses
+
+#### Match Types
+- **Broad Match Modified**: Use for wider reach with some control
+- **Phrase Match**: Good balance between reach and relevance
+- **Exact Match**: Highest relevance but limited reach
+- **Use a Mix**: Implement a tiered approach with different match types
+
+#### Negative Keywords
+- **Add Irrelevant Terms**: Exclude searches that aren't relevant to your business
+- **Filter Out Window Shoppers**: Exclude terms like "free," "cheap," or "DIY" if you're selling premium services
+- **Regularly Review Search Terms**: Add new negative keywords based on actual searches
+- **Use Negative Keyword Lists**: Create reusable lists for common exclusions
+""")
+
+st.info("""
+**Pro Tip**: Start with phrase and exact match keywords, then use the Search Terms report to identify new keyword opportunities and negative keywords.
+""")
+
+with bp_tabs[2]:
+st.markdown("""
+### Landing Page Best Practices
+
+#### Relevance
+- **Match Ad Copy**: Ensure your landing page content aligns with your ad
+- **Use Same Keywords**: Include the same keywords from your ad in your landing page
+- **Fulfill the Promise**: Deliver what your ad offered
+- **Clear Value Proposition**: Communicate your unique value immediately
+
+#### User Experience
+- **Fast Loading Speed**: Optimize for quick loading (under 3 seconds)
+- **Mobile Optimization**: Ensure perfect display on all devices
+- **Clear Navigation**: Make it easy for users to find what they need
+- **Minimal Distractions**: Remove unnecessary elements that don't support conversion
+
+#### Conversion Optimization
+- **Prominent CTA**: Make your call-to-action button stand out
+- **Reduce Form Fields**: Ask for only essential information
+- **Add Trust Signals**: Include testimonials, reviews, and security badges
+- **A/B Test**: Continuously test different landing page elements
+""")
+
+st.info("""
+**Pro Tip**: Create dedicated landing pages for each ad group rather than sending all traffic to your homepage for higher conversion rates.
+""")
+
+with bp_tabs[3]:
+st.markdown("""
+### Quality Score Optimization
+
+#### What Affects Quality Score
+- **Click-Through Rate (CTR)**: The most important factor
+- **Ad Relevance**: How closely your ad matches the search intent
+- **Landing Page Experience**: Relevance, transparency, and navigation
+- **Expected Impact**: Google's prediction of how your ad will perform
+
+#### Improving Quality Score
+- **Tightly Themed Ad Groups**: Create small, focused ad groups with related keywords
+- **Relevant Ad Copy**: Ensure your ads directly address the search query
+- **Optimize Landing Pages**: Create specific landing pages for each ad group
+- **Improve CTR**: Test different ad variations to find what drives the highest CTR
+- **Use Ad Extensions**: Extensions improve visibility and relevance
+
+#### Benefits of High Quality Score
+- **Lower Costs**: Higher quality scores can reduce your CPC
+- **Better Ad Positions**: Improved rank in the auction
+- **Higher ROI**: Better performance for the same budget
+""")
+
+st.info("""
+**Pro Tip**: A 1-point improvement in Quality Score can reduce your CPC by up to 16% according to industry studies.
+""")
+
+with bp_tabs[4]:
+st.markdown("""
+### Ad Extensions Best Practices
+
+#### Sitelink Extensions
+- **Use Descriptive Text**: Clearly explain where each link leads
+- **Create Unique Links**: Each sitelink should go to a different landing page
+- **Include 6+ Sitelinks**: Give Google options to show the most relevant ones
+- **Add Descriptions**: Two description lines provide more context
+
+#### Callout Extensions
+- **Highlight Benefits**: Focus on unique selling points
+- **Keep It Short**: 12-15 characters is optimal
+- **Add 8+ Callouts**: Give Google plenty of options
+- **Be Specific**: "24/7 Customer Support" is better than "Great Service"
+
+#### Structured Snippet Extensions
+- **Choose Relevant Headers**: Select the most applicable category
+- **Add Comprehensive Values**: Include all relevant options
+- **Be Concise**: Keep each value short and clear
+- **Create Multiple Snippets**: Different headers for different ad groups
+
+#### Other Extensions
+- **Call Extensions**: Add your phone number for call-focused campaigns
+- **Location Extensions**: Link your Google Business Profile
+- **Price Extensions**: Showcase products or services with prices
+- **App Extensions**: Promote your mobile app
+- **Lead Form Extensions**: Collect leads directly from your ad
+""")
+
+st.info("""
+**Pro Tip**: Ad extensions are free to add and can significantly increase your ad's CTR by providing additional information and increasing your ad's size on the search results page.
+""")
+
+# Additional resources
+st.subheader("Additional Resources")
+
+col1, col2, col3 = st.columns(3)
+
+with col1:
+st.markdown("""
+#### Google Resources
+- [Google Ads Help Center](https://support.google.com/google-ads/)
+- [Google Ads Best Practices](https://support.google.com/google-ads/topic/3119143)
+- [Google Ads Academy](https://skillshop.withgoogle.com/google-ads)
+""")
+
+with col2:
+st.markdown("""
+#### Tools
+- [Google Keyword Planner](https://ads.google.com/home/tools/keyword-planner/)
+- [Google Ads Editor](https://ads.google.com/home/tools/ads-editor/)
+- [Google Ads Preview Tool](https://ads.google.com/aw/tools/ad-preview)
+""")
+
+with col3:
+st.markdown("""
+#### Learning Resources
+- [Google Ads Certification](https://skillshop.withgoogle.com/google-ads)
+- [Google Ads YouTube Channel](https://www.youtube.com/user/learnwithgoogle)
+- [Google Ads Blog](https://blog.google/products/ads/)
+""")
+
+if __name__ == "__main__":
+write_google_ads()
\ No newline at end of file
diff --git a/lib/ai_writers/ai_blog_faqs_writer/faqs_generator_blog.py b/lib/ai_writers/ai_blog_faqs_writer/faqs_generator_blog.py
index 8a8f8ea6..cefab088 100644
--- a/lib/ai_writers/ai_blog_faqs_writer/faqs_generator_blog.py
+++ b/lib/ai_writers/ai_blog_faqs_writer/faqs_generator_blog.py
@@ -7,6 +7,7 @@ well-researched FAQs from various content sources with customizable options.
import sys
import json
+import re
from typing import Dict, List, Optional, Union
from pathlib import Path
from enum import Enum
@@ -15,12 +16,12 @@ from loguru import logger
from lib.gpt_providers.text_generation.main_text_generation import llm_text_gen
from lib.ai_web_researcher.google_serp_search import google_search
-from lib.ai_web_researcher.tavily_ai_search import tavily_search
+from lib.ai_web_researcher.tavily_ai_search import do_tavily_ai_search
from lib.ai_web_researcher.metaphor_basic_neural_web_search import metaphor_search_articles
logger.remove()
logger.add(sys.stdout,
- colorize=True,
+ colorize=True,
format="
{faq.code_example}
+ {faq.code_example}
+