From 9409e57d2fd7d23084eeb5a52108bb5b8894dad9 Mon Sep 17 00:00:00 2001 From: ajaysi Date: Thu, 26 Sep 2024 08:16:22 +0530 Subject: [PATCH] Performance optimizations, Improved SEO tools & error handling --- README.md | 1 + alwrity.py | 153 +-------- lib/ai_marketing_tools/.ai_backlinking.py.swp | Bin 0 -> 24576 bytes lib/ai_marketing_tools/ai_backlinking.py | 302 ++++++++++++++++++ .../backlinking_ui_streamlit.py | 60 ++++ .../.gpt_online_researcher.py.swp | Bin 0 -> 16384 bytes lib/ai_writers/data_img_slides_analyst.py | 0 lib/utils/alwrity_utils.py | 47 --- lib/utils/api_key_manager.py | 2 + lib/utils/content_generators.py | 4 +- lib/utils/seo_tools.py | 84 +++-- lib/utils/ui_setup.py | 5 +- requirements.txt | 1 + 13 files changed, 442 insertions(+), 217 deletions(-) create mode 100644 lib/ai_marketing_tools/.ai_backlinking.py.swp create mode 100644 lib/ai_marketing_tools/ai_backlinking.py create mode 100644 lib/ai_marketing_tools/backlinking_ui_streamlit.py create mode 100644 lib/ai_web_researcher/.gpt_online_researcher.py.swp create mode 100644 lib/ai_writers/data_img_slides_analyst.py diff --git a/README.md b/README.md index e8c50836..86e7514b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ Our toolkit integrates **(OpenAI, Gemini, Anthropic)** AI models for text genera - ![ALwrity AI SEO Tools](https://github.com/AJaySi/AI-Writer/wiki/ALwrity-AI-SEO-Tools) - ![ALwrity Web Researcher](https://github.com/AJaySi/AI-Writer/wiki/Alwrity-AI-Web-Research-Details-for-content-writing) - RoadMap - Coming Soon.. +- Present Focus: Nextjs react Alwrity App - Coming Soon.. --- > ![](https://github.com/AJaySi/AI-Writer/blob/main/lib/workspace/keyword_blog.gif) diff --git a/alwrity.py b/alwrity.py index 977b1dae..785dc930 100644 --- a/alwrity.py +++ b/alwrity.py @@ -3,98 +3,25 @@ import os import json import base64 from datetime import datetime -import streamlit as st -from lib.utils.environment_utils import load_environment +from dotenv import load_dotenv + from lib.utils.config_manager import save_config from lib.utils.ui_setup import setup_ui from lib.utils.api_key_manager import check_api_keys, check_llm_environs from lib.utils.content_generators import ai_writers, content_planning_tools, blog_from_keyword, story_input_section, essay_writer, ai_news_writer, ai_finance_ta_writer, write_ai_prod_desc, do_web_research, competitor_analysis, ai_agents_content_planner from lib.utils.seo_tools import ai_seo_tools +from lib.utils.ui_setup import setup_ui, setup_tabs from lib.utils.alwrity_utils import ai_agents_team, ai_social_writer from lib.utils.file_processor import load_image, read_prompts, write_prompts from lib.utils.voice_processing import record_voice -# Placeholder function definitions for missing functions -def blog_from_audio(): - """Placeholder for the blog_from_audio function.""" - st.write("This is a placeholder for the blog_from_audio function.") + def process_folder_for_rag(folder_path): """Placeholder for the process_folder_for_rag function.""" st.write(f"This is a placeholder for processing the folder: {folder_path}") -@st.cache_data -def check_api_keys(): - """ - Checks if the required API keys are present in the environment variables. - Prompts the user to enter missing keys and saves them in the .env file. - """ - api_keys = { - "METAPHOR_API_KEY": "https://dashboard.exa.ai/login", - "TAVILY_API_KEY": "https://tavily.com/#api", - "SERPER_API_KEY": "https://serper.dev/signup", - "STABILITY_API_KEY": "https://platform.stability.ai/", - "FIRECRAWL_API_KEY": "https://www.firecrawl.dev/account" - } - - missing_keys = { - key: url for key, url in api_keys.items() if os.getenv(key) is None - } - - if missing_keys: - st.error("๐Ÿšจ Some API keys are missing! Please provide them below:") - for key, url in missing_keys.items(): - api_key = st.text_input(f"Enter ๐Ÿ” {key}: ๐Ÿ‘‰[Get it here]({url})๐Ÿ‘ˆ") - if api_key: - os.environ[key] = api_key - try: - with open(".env", "a") as env_file: - env_file.write(f"{key}={api_key}\n") - except IOError as e: - st.error(f"Failed to write {key} to .env file: {e}") - st.success(f"โœ… {key} added successfully!") - return False - return True - - -@st.cache_data -def check_llm_environs(): - """ - Ensures that the LLM provider and corresponding API key are set. - Prompts the user to select a provider and enter the API key if missing. - """ - gpt_provider = os.getenv("GPT_PROVIDER") - supported_providers = { - 'google': "GEMINI_API_KEY", - 'openai': "OPENAI_API_KEY", - 'mistralai': "MISTRAL_API_KEY" - } - - if not gpt_provider or gpt_provider.lower() not in supported_providers: - gpt_provider = st.selectbox( - "Select your LLM Provider", options=list(supported_providers.keys()) - ) - os.environ["GPT_PROVIDER"] = gpt_provider - try: - with open(".env", "a") as env_file: - env_file.write(f"GPT_PROVIDER={gpt_provider}\n") - except IOError as e: - st.error(f"Failed to write GPT_PROVIDER to .env file: {e}") - st.success(f"GPT Provider set to {gpt_provider}") - - api_key_var = supported_providers[gpt_provider.lower()] - if not os.getenv(api_key_var): - api_key = st.text_input(f"Enter {api_key_var}:") - if api_key: - os.environ[api_key_var] = api_key - with open(".env", "a") as env_file: - env_file.write(f"{api_key_var}={api_key}\n") - st.success(f"{api_key_var} added successfully!") - return False - return True - - def save_config(config): """ Saves the provided configuration dictionary to a JSON file specified by the environment variable. @@ -281,30 +208,10 @@ def sidebar_configuration(): -# Function to read prompts from the file -@st.cache_data -def read_prompts(file_path="prompt_llm.txt"): - if os.path.exists(file_path): - with open(file_path, "r") as file: - prompts = file.readlines() - return [prompt.strip() for prompt in prompts] - return [] - -# Function to write prompts to the file -def write_prompts(prompts, file_path="prompt_llm.txt"): - with open(file_path, "w") as file: - for prompt in prompts: - file.write(f"{prompt}\n") - -# Function to load and encode the image file -def load_image(image_path): - with open(image_path, "rb") as img_file: - b64_string = base64.b64encode(img_file.read()).decode() - return b64_string - - def main(): - load_environment() + #load_environment + from dotenv import load_dotenv + load_dotenv() setup_ui() setup_environment_paths() sidebar_configuration() @@ -314,26 +221,6 @@ def main(): modify_prompts_sidebar() -def setup_ui(): - """Sets up the Streamlit UI with custom CSS and logo.""" - try: - css_file_path = os.path.join('lib', 'workspace', 'alwrity_ui_styling.css') - with open(css_file_path) as f: - custom_css = f.read() - st.set_page_config(page_title="Alwrity", layout="wide") - st.markdown(f'', unsafe_allow_html=True) - except Exception as err: - st.error(f"Failed in setting up Alwrity Streamlit UI: {err}") - - image_base64 = load_image("lib/workspace/alwrity_logo.png") - st.markdown(f""" -
- Alwrity Logo - Welcome to Alwrity! -
- """, unsafe_allow_html=True) - - def setup_environment_paths(): """Sets up environment paths for saving files and configurations.""" os.environ["SEARCH_SAVE_FILE"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_web_research", @@ -344,32 +231,6 @@ def setup_environment_paths(): os.environ["ALWRITY_CONFIG"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_config", "main_config.json") -def setup_tabs(): - """Sets up the main tabs in the Streamlit app.""" - tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs( - ["๐Ÿ“…Content Planning", " ๐Ÿ“๐Ÿค–AI Writers", "๐Ÿค๐Ÿค–Agents Teams", "๐Ÿ› ๏ธ๐Ÿ”AI SEO tools", "๐Ÿ“ฑAI Social Tools", " ๐Ÿ’ฌAsk Alwrity"]) - with tab1: - content_planning_tools() - - with tab2: - ai_writers() - - with tab3: - ai_agents_team() - - with tab4: - ai_seo_tools() - - with tab5: - ai_social_writer() - - with tab6: - st.subheader("Chat with your Data, Chat with any Data.. COMING SOON !") - st.markdown("Create a collection by uploading files (PDF, MD, CSV, etc), or crawl a data source (Websites, more sources coming soon.") - st.markdown("One can ask/chat, summarize and do semantic search over the uploaded data") - # alwrity_chat_docqa() - - def modify_prompts_sidebar(): """Provides a sidebar for modifying prompts.""" st.sidebar.title("๐Ÿ“ Modify Prompts") diff --git a/lib/ai_marketing_tools/.ai_backlinking.py.swp b/lib/ai_marketing_tools/.ai_backlinking.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..887420ef707b503c8bfd4804119c3fcff5873544 GIT binary patch literal 24576 zcmeI4dyHgRUB_#ehYwg@CdL5D-5QeZZo6w(kObO&(9`qS4l_&dbkB}3nKZYnZdKo% zs=BrJ-kP3fXjl~$l@LOF5kaCRA`$`-VPiyDjm8-H!v}$gi6TKlgcu&aAc%gxzjMy5 zTirdgtI>Z*Rq~zcs(bG_zwEVk4tzUtpd3B9@kSPOt6$VT{{5B%?@#uh*Zljv2d+QGe}1ihfAfLs zPx7D7`1dayxb8pB-ew$_abU)Q83$$@m~mjnff)y89GG!n#(^0JW*nGt;QxUGai`Hx zO#f;H{M7$L{QqyyY&8A_Job!6B}5(RdMf4)~|1HX7H! zHux6FhWCT_fwzMz;L{{1J_3Fiyc|3me2t{TYrtLLuSszHCHN!o82EK?9DI^>e*%06 zhzCCc{!d=VBL6y@Tut)0mqaUTQJF>UJc-LB8YOv=4dZ_Lx}*~≧LM(YT=BAu4y0 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 b1dTm&#a_`W$_}=*`kJ5I^7DbY`Nn?(9-9y2 literal 0 HcmV?d00001 diff --git a/lib/ai_marketing_tools/ai_backlinking.py b/lib/ai_marketing_tools/ai_backlinking.py new file mode 100644 index 00000000..d2c1b00a --- /dev/null +++ b/lib/ai_marketing_tools/ai_backlinking.py @@ -0,0 +1,302 @@ +#Problem: +# +#Finding websites for guest posts is manual, tedious, and time-consuming. Communicating with webmasters, maintaining conversations, and keeping track of backlinking opportunities is difficult to scale. Content creators and marketers struggle with discovering new websites and consistently getting backlinks. +#Solution: +# +#An AI-powered backlinking app that automates web research, scrapes websites, extracts contact information, and sends personalized outreach emails to webmasters. This would simplify the entire process, allowing marketers to scale their backlinking strategy with minimal manual intervention. +#Core Workflow: +# +# User Input: +# Keyword Search: The user inputs a keyword (e.g., "AI writers"). +# Search Queries: Your app will append various search strings to this keyword to find backlinking opportunities (e.g., "AI writers + 'Write for Us'"). +# +# Web Research: +# +# Use search engines or web scraping to run multiple queries: +# Keyword + "Guest Contributor" +# Keyword + "Add Guest Post" +# Keyword + "Write for Us", etc. +# +# Collect URLs of websites that have pages or posts related to guest post opportunities. +# +# Scrape Website Data: +# Contact Information Extraction: +# Scrape the website for contact details (email addresses, contact forms, etc.). +# Use natural language processing (NLP) to understand the type of content on the website and who the contact person might be (webmaster, editor, or guest post manager). +# Website Content Understanding: +# Scrape a summary of each websiteโ€™s content (e.g., their blog topics, categories, and tone) to personalize the email based on the site's focus. +# +# Personalized Outreach: +# AI Email Composition: +# Compose personalized outreach emails based on: +# The scraped data (website content, topic focus, etc.). +# The user's input (what kind of guest post or content they want to contribute). +# Example: โ€œHi [Webmaster Name], I noticed that your site [Site Name] features high-quality content about [Topic]. I would love to contribute a guest post on [Proposed Topic] in exchange for a backlink.โ€ +# +# Automated Email Sending: +# Review Emails (Optional HITL): +# Let users review and approve the personalized emails before they are sent, or allow full automation. +# Send Emails: +# Automate email dispatch through an integrated SMTP or API (e.g., Gmail API, SendGrid). +# Keep track of which emails were sent, bounced, or received replies. +# +# Scaling the Search: +# Repeat for Multiple Keywords: +# Run the same scraping and outreach process for a list of relevant keywords, either automatically suggested or uploaded by the user. +# Keep Track of Sent Emails: +# Maintain a log of all sent emails, responses, and follow-up reminders to avoid repetition or forgotten leads. +# +# Tracking Responses and Follow-ups: +# Automated Responses: +# If a website replies positively, AI can respond with predefined follow-up emails (e.g., proposing topics, confirming submission deadlines). +# Follow-up Reminders: +# If thereโ€™s no reply, the system can send polite follow-up reminders at pre-set intervals. +# +#Key Features: +# +# Automated Web Scraping: +# Scrape websites for guest post opportunities using a predefined set of search queries based on user input. +# Extract key information like email addresses, names, and submission guidelines. +# +# Personalized Email Writing: +# Leverage AI to create personalized emails using the scraped website information. +# Tailor each email to the tone, content style, and focus of the website. +# +# Email Sending Automation: +# Integrate with email platforms (e.g., Gmail, SendGrid, or custom SMTP). +# Send automated outreach emails with the ability for users to review first (HITL - Human-in-the-loop) or automate completely. +# +# Customizable Email Templates: +# Allow users to customize or choose from a set of email templates for different types of outreach (e.g., guest post requests, follow-up emails, submission offers). +# +# Lead Tracking and Management: +# Track all emails sent, monitor replies, and keep track of successful backlinks. +# Log each leadโ€™s status (e.g., emailed, responded, no reply) to manage future interactions. +# +# Multiple Keywords/Queries: +# Allow users to run the same process for a batch of keywords, automatically generating relevant search queries for each. +# +# AI-Driven Follow-Up: +# Schedule follow-up emails if there is no response after a specified period. +# +# Reports and Analytics: +# Provide users with reports on how many emails were sent, opened, replied to, and successful backlink placements. +# +#Advanced Features (for Scaling and Optimization): +# +# Domain Authority Filtering: +# Use SEO APIs (e.g., Moz, Ahrefs) to filter websites based on their domain authority or backlink strength. +# Prioritize high-authority websites to maximize the impact of backlinks. +# +# Spam Detection: +# Use AI to detect and avoid spammy or low-quality websites that might harm the userโ€™s SEO. +# +# Contact Form Auto-Fill: +# If the site only offers a contact form (without email), automatically fill and submit the form with AI-generated content. +# +# Dynamic Content Suggestions: +# Suggest guest post topics based on the websiteโ€™s focus, using NLP to analyze the site's existing content. +# +# Bulk Email Support: +# Allow users to bulk-send outreach emails while still personalizing each message for scalability. +# +# AI Copy Optimization: +# Use copywriting AI to optimize email content, adjusting tone and CTA based on the target audience. +# +#Challenges and Considerations: +# +# Legal Compliance: +# Ensure compliance with anti-spam laws (e.g., CAN-SPAM, GDPR) by including unsubscribe options or manual email approval. +# +# Scraping Limits: +# Be mindful of scraping limits on certain websites and employ smart throttling or use API-based scraping for better reliability. +# +# Deliverability: +# Ensure emails are delivered properly without landing in spam folders by integrating proper email authentication (SPF, DKIM) and using high-reputation SMTP servers. +# +# Maintaining Email Personalization: +# Striking the balance between automating the email process and keeping each message personal enough to avoid being flagged as spam. +# +#Technology Stack: +# +# Web Scraping: BeautifulSoup, Scrapy, or Puppeteer for scraping guest post opportunities and contact information. +# Email Automation: Integrate with Gmail API, SendGrid, or Mailgun for sending emails. +# NLP for Personalization: GPT-based models for email generation and web content understanding. +# Frontend: React or Vue for the user interface. +# Backend: Python/Node.js with Flask or Express for the API and automation logic. +# Database: MongoDB or PostgreSQL to track leads, emails, and responses. +# +#This solution will significantly streamline the backlinking process by automating the most tedious tasks, from finding sites to personalizing outreach, enabling marketers to focus on content creation and high-level strategies. + + +import sys +from googlesearch import search +from loguru import logger +# Configure logger +logger.remove() +logger.add(sys.stdout, + colorize=True, + format="{level}|{file}:{line}:{function}| {message}" + ) + +from lib.ai_web_researcher.firecrawl_web_crawler import scrape_website +from lib.gpt_providers.text_generation.main_text_generation import llm_text_gen +from lib.ai_web_researcher.firecrawl_web_crawler import scrape_url + + +def generate_search_queries(keyword): + """ + Generate a list of search queries for finding guest post opportunities. + + Args: + keyword (str): The keyword to base the search queries on. + + Returns: + list: A list of search queries. + """ + return [ + f"{keyword} + 'Guest Contributor'", +# f"{keyword} + 'Add Guest Post'", +# f"{keyword} + 'Guest Bloggers Wanted'", +# f"{keyword} + 'Write for Us'", +# f"{keyword} + 'Submit Guest Post'", +# f"{keyword} + 'Become a Guest Blogger'", +# f"{keyword} + 'guest post opportunities'", +# f"{keyword} + 'Submit article'", + ] + + +def find_backlink_opportunities(keyword): + """ + Find backlink opportunities by scraping websites based on search queries. + + Args: + keyword (str): The keyword to search for backlink opportunities. + + Returns: + list: A list of results from the scraped websites. + """ + search_queries = generate_search_queries(keyword) + results = [] + + for query in search_queries: + urls = search_for_urls(query) + for url in urls: + website_data = scrape_website(url) + logger.info(f"Scraped Website content for {url}: {website_data}") + if website_data: + contact_info = extract_contact_info(website_data) + logger.info("Contact details found for {url}: [contact_info]") + + # AI-driven insights using website data + insights_prompt = f""" +You are an expert in analyzing website content. Below is the content of a website. Please analyze it and provide actionable insights for a personalized guest post outreach: + +Website Content: +{website_data.get("content_summary", "")} + +1. **Website Focus**: What is the primary topic, audience, and tone? +2. **Guest Posting Guidelines**: Are there any guest post preferences (content type, length, etc.)? +3. **Suggested Topics**: Based on the siteโ€™s content, what topics might align well? +4. **Personalization Tips**: How can we make the outreach more tailored to this site? +""" + + insights = llm_text_gen(insights_prompt) + + detailed_result = { + "url": url, + "metadata": { + "title": website_data.get("metadata", {}).get("title", ""), + "description": website_data.get("metadata", {}).get("description", ""), + "keywords": website_data.get("metadata", {}).get("keywords", []), + }, + "content_summary": website_data.get("content_summary", ""), + "contact_info": contact_info, + "insights": insights, + "backlink_opportunity": { + "query": query, + "context": "Guest post opportunity" + } + } + results.append(detailed_result) + + return results + + +def compose_personalized_email(website_data, insights, user_proposal): + """ + Compose a personalized outreach email using AI LLM based on website data, insights, and user proposal. + + Args: + website_data (dict): The data of the website including metadata and contact info. + insights (str): Insights generated by the LLM about the website. + user_proposal (dict): The user's proposal for a guest post or content contribution. + + Returns: + str: A personalized email message. + """ + contact_name = website_data.get("contact_info", {}).get("name", "Webmaster") + site_name = website_data.get("metadata", {}).get("title", "your site") + proposed_topic = user_proposal.get("topic", "a guest post") + user_name = user_proposal.get("user_name", "Your Name") + user_email = user_proposal.get("user_email", "your_email@example.com") + + # Refined prompt for email generation + email_prompt = f""" +You are an AI assistant tasked with composing a highly personalized outreach email for guest posting. + +Contact Name: {contact_name} +Website Name: {site_name} +Proposed Topic: {proposed_topic} + +User Details: +Name: {user_name} +Email: {user_email} + +Website Insights: {insights} + +Please compose a professional and engaging email that includes: +1. A personalized introduction addressing the recipient. +2. A mention of the website's content focus. +3. A proposal for a guest post. +4. A call to action to discuss the guest post opportunity. +5. A polite closing with user contact details. +""" + + return llm_text_gen(email_prompt) + + +def search_for_urls(query): + """ + Search for URLs based on a query using Firecrawl. + + Args: + query (str): The search query. + + Returns: + list: A list of URLs. + """ + # We can use Firecrawl, which also provides AI extraction. + try: + google_search_result = search(query, max_results=5) + print(google_search_result) + return google_search_result + except Exception as err: + logger.error("Failed to do GoogleSearch: {err}") + + +def extract_contact_info(website_data): + """ + Extract contact information from website data. + + Args: + website_data (dict): Scraped data from the website. + + Returns: + dict: Extracted contact information such as name, email, etc. + """ + # Placeholder for extracting contact information logic + return { + "name": website_data.get("contact", {}).get("name", "Webmaster"), + "email": website_data.get("contact", {}).get("email", ""), + } diff --git a/lib/ai_marketing_tools/backlinking_ui_streamlit.py b/lib/ai_marketing_tools/backlinking_ui_streamlit.py new file mode 100644 index 00000000..3b57319d --- /dev/null +++ b/lib/ai_marketing_tools/backlinking_ui_streamlit.py @@ -0,0 +1,60 @@ +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 + + +# Streamlit UI function +def backlinking_ui(): + st.title("AI Backlinking Tool") + + # Step 1: Get user inputs + keyword = st.text_input("Enter a keyword", value="technology") + + # Step 2: Generate backlink opportunities + if st.button("Find Backlink Opportunities"): + if keyword: + backlink_opportunities = find_backlink_opportunities(keyword) + + # Convert results to a DataFrame for display + df = pd.DataFrame(backlink_opportunities) + + # Create a selectable table using st-aggrid + gb = GridOptionsBuilder.from_dataframe(df) + gb.configure_selection('multiple', use_checkbox=True, groupSelectsChildren=True) + gridOptions = gb.build() + + grid_response = AgGrid( + df, + gridOptions=gridOptions, + update_mode=GridUpdateMode.SELECTION_CHANGED, + height=200, + width='100%' + ) + + selected_rows = grid_response['selected_rows'] + + if selected_rows: + st.write("Selected Opportunities:") + st.table(pd.DataFrame(selected_rows)) + + # Step 3: Option to generate personalized emails for selected opportunities + if st.button("Generate Emails for Selected Opportunities"): + user_proposal = { + "user_name": st.text_input("Your Name", value="John Doe"), + "user_email": st.text_input("Your Email", value="john@example.com") + } + + emails = [] + for selected in selected_rows: + insights = f"Insights based on content from {selected['url']}." + email = compose_personalized_email(selected, insights, user_proposal) + emails.append(email) + + st.subheader("Generated Emails:") + for email in emails: + st.write(email) + st.markdown("---") + + else: + st.error("Please enter a keyword.") diff --git a/lib/ai_web_researcher/.gpt_online_researcher.py.swp b/lib/ai_web_researcher/.gpt_online_researcher.py.swp new file mode 100644 index 0000000000000000000000000000000000000000..1dd76695784a03bcec06f880faafe02f360a85f3 GIT binary patch literal 16384 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 literal 0 HcmV?d00001 diff --git a/lib/ai_writers/data_img_slides_analyst.py b/lib/ai_writers/data_img_slides_analyst.py new file mode 100644 index 00000000..e69de29b diff --git a/lib/utils/alwrity_utils.py b/lib/utils/alwrity_utils.py index cdeab67e..1b1cba85 100644 --- a/lib/utils/alwrity_utils.py +++ b/lib/utils/alwrity_utils.py @@ -23,15 +23,6 @@ import PyPDF2 import tiktoken import openai from lib.gpt_providers.text_to_image_generation.main_generate_image_from_prompt import generate_image -from lib.ai_seo_tools.seo_structured_data import ai_structured_data -from lib.ai_seo_tools.content_title_generator import ai_title_generator -from lib.ai_seo_tools.meta_desc_generator import metadesc_generator_main -from lib.ai_seo_tools.image_alt_text_generator import alt_text_gen -from lib.ai_seo_tools.opengraph_generator import og_tag_generator -from lib.ai_seo_tools.optimize_images_for_upload import main_img_optimizer -from lib.ai_seo_tools.google_pagespeed_insights import google_pagespeed_insights -from lib.ai_seo_tools.on_page_seo_analyzer import analyze_onpage_seo -from lib.ai_seo_tools.weburl_seo_checker import url_seo_checker from lib.utils.voice_processing import record_voice from lib.content_planning_calender.content_planning_agents_alwrity_crew import ai_agents_content_planner from ..gpt_providers.text_generation.main_text_generation import llm_text_gen @@ -87,44 +78,6 @@ def process_input(input_text, uploaded_file): return None -def ai_seo_tools(): - """ Collection SEO tools for content creators. """ - options = [ - "Generate Structured Data - Rich Snippet", - "Generate SEO optimized Blog Titles", - "Generate Meta Description for SEO", - "Generate Image Alt Text", - "Generate OpenGraph Tags", - "Optimize/Resize Image", - "Run Google PageSpeed Insights", - "Analyze On Page SEO", - "URL SEO Checker" - ] - - # Using st.radio instead of st.selectbox - choice = st.radio("**๐Ÿ‘‡ Select AI SEO Tool:**", options, index=0, format_func=lambda x: f"๐Ÿ“ {x}") - - # Handle choices based on the selected option - if choice == "Generate Structured Data - Rich Snippet": - ai_structured_data() - elif choice == "Generate Meta Description for SEO": - metadesc_generator_main() - elif choice == "Generate SEO optimized Blog Titles": - ai_title_generator() - elif choice == "Generate Image Alt Text": - alt_text_gen() - elif choice == "Generate OpenGraph Tags": - og_tag_generator() - elif choice == "Optimize/Resize Image": - main_img_optimizer() - elif choice == "Run Google PageSpeed Insights": - google_pagespeed_insights() - elif choice == "Analyze On Page SEO": - analyze_onpage_seo() - elif choice == "URL SEO Checker": - url_seo_checker() - - def blog_from_keyword(): """ Input blog keywords, research and write a factual blog.""" st.header("Blog Content Writer") diff --git a/lib/utils/api_key_manager.py b/lib/utils/api_key_manager.py index 8af8243d..43b0fa54 100644 --- a/lib/utils/api_key_manager.py +++ b/lib/utils/api_key_manager.py @@ -34,6 +34,8 @@ def check_api_keys(): return False return True + + @st.cache_data def check_llm_environs(): """ diff --git a/lib/utils/content_generators.py b/lib/utils/content_generators.py index 91954d2d..c26ccf6b 100644 --- a/lib/utils/content_generators.py +++ b/lib/utils/content_generators.py @@ -1,11 +1,13 @@ import streamlit as st from lib.utils.alwrity_utils import ( - blog_from_keyword, ai_agents_team, essay_writer, ai_news_writer, ai_seo_tools, + blog_from_keyword, ai_agents_team, essay_writer, ai_news_writer, ai_finance_ta_writer, ai_social_writer, do_web_research, competitor_analysis ) from lib.ai_writers.ai_story_writer.story_writer import story_input_section from lib.ai_writers.ai_product_description_writer import write_ai_prod_desc from lib.content_planning_calender.content_planning_agents_alwrity_crew import ai_agents_content_planner +from lib.utils.seo_tools import ai_seo_tools + def ai_writers(): options = [ diff --git a/lib/utils/seo_tools.py b/lib/utils/seo_tools.py index a2337eac..daa36980 100644 --- a/lib/utils/seo_tools.py +++ b/lib/utils/seo_tools.py @@ -8,40 +8,80 @@ from lib.ai_seo_tools.optimize_images_for_upload import main_img_optimizer from lib.ai_seo_tools.google_pagespeed_insights import google_pagespeed_insights from lib.ai_seo_tools.on_page_seo_analyzer import analyze_onpage_seo from lib.ai_seo_tools.weburl_seo_checker import url_seo_checker +from lib.ai_marketing_tools.backlinking_ui_streamlit import backlinking_ui + def ai_seo_tools(): - """ Collection SEO tools for content creators. """ + """ + A collection of AI-powered SEO tools for content creators, providing various options + such as generating structured data, optimizing images, checking page speed, + and analyzing on-page SEO. + """ + st.markdown( + """ + Welcome to your one-stop solution for AI-driven SEO optimization. Select a tool from the options below + to improve your websiteโ€™s SEO with cutting-edge AI technology. + """ + ) + # List of SEO tools with unique emojis for each option options = [ - "Generate Structured Data - Rich Snippet", - "Generate SEO optimized Blog Titles", - "Generate Meta Description for SEO", - "Generate Image Alt Text", - "Generate OpenGraph Tags", - "Optimize/Resize Image", - "Run Google PageSpeed Insights", - "Analyze On Page SEO", - "URL SEO Checker" + "๐Ÿ“ Generate Structured Data - Rich Snippet", + "โœ๏ธ Generate SEO Optimized Blog Titles", + "๐Ÿ“ Generate Meta Description for SEO", + "๐Ÿ–ผ๏ธ Generate Image Alt Text", + "๐Ÿ“„ Generate OpenGraph Tags", + "๐Ÿ“‰ Optimize/Resize Image", + "โšก Run Google PageSpeed Insights", + "๐Ÿ” Analyze On-Page SEO", + "๐ŸŒ URL SEO Checker", + "๐Ÿ”— AI Backlinking Tool" ] - # Using st.radio instead of st.selectbox - choice = st.radio("**๐Ÿ‘‡ Select AI SEO Tool:**", options, index=0, format_func=lambda x: f"๐Ÿ“ {x}") + # User selection of SEO tools using radio buttons + choice = st.radio( + "**๐Ÿ‘‡ Select an AI SEO Tool:**", + options, + index=0, + format_func=lambda x: x + ) - # Handle choices based on the selected option - if choice == "Generate Structured Data - Rich Snippet": + # Call the respective functions based on the user selection + if choice == "๐Ÿ“ Generate Structured Data - Rich Snippet": + # Generate Structured Data for Rich Snippets ai_structured_data() - elif choice == "Generate Meta Description for SEO": + + elif choice == "๐Ÿ“ Generate Meta Description for SEO": + # Generate SEO-optimized meta descriptions metadesc_generator_main() - elif choice == "Generate SEO optimized Blog Titles": + + elif choice == "โœ๏ธ Generate SEO Optimized Blog Titles": + # Generate SEO-friendly blog titles ai_title_generator() - elif choice == "Generate Image Alt Text": + + elif choice == "๐Ÿ–ผ๏ธ Generate Image Alt Text": + # Generate alternative text for images alt_text_gen() - elif choice == "Generate OpenGraph Tags": + + elif choice == "๐Ÿ“„ Generate OpenGraph Tags": + # Generate OpenGraph tags for social media sharing og_tag_generator() - elif choice == "Optimize/Resize Image": + + elif choice == "๐Ÿ“‰ Optimize/Resize Image": + # Optimize images by resizing or compressing them main_img_optimizer() - elif choice == "Run Google PageSpeed Insights": + + elif choice == "โšก Run Google PageSpeed Insights": + # Run Google PageSpeed Insights for performance analysis google_pagespeed_insights() - elif choice == "Analyze On Page SEO": + + elif choice == "๐Ÿ” Analyze On-Page SEO": + # Analyze on-page SEO elements analyze_onpage_seo() - elif choice == "URL SEO Checker": + + elif choice == "๐ŸŒ URL SEO Checker": + # Check SEO health of a specific URL url_seo_checker() + + elif choice == "๐Ÿ”— AI Backlinking Tool": + # Run AI Backlinking tool for link-building opportunities + backlinking_ui() diff --git a/lib/utils/ui_setup.py b/lib/utils/ui_setup.py index bddbdf3b..799dde53 100644 --- a/lib/utils/ui_setup.py +++ b/lib/utils/ui_setup.py @@ -2,7 +2,9 @@ import os import streamlit as st from .file_processor import load_image from .content_generators import content_planning_tools, ai_writers -from .alwrity_utils import ai_agents_team, ai_seo_tools, ai_social_writer +from .alwrity_utils import ai_agents_team, ai_social_writer +from .seo_tools import ai_seo_tools + def setup_ui(): """Sets up the Streamlit UI with custom CSS and logo.""" @@ -23,6 +25,7 @@ def setup_ui(): """, unsafe_allow_html=True) + def setup_tabs(): """Sets up the main tabs in the Streamlit app.""" tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs( diff --git a/requirements.txt b/requirements.txt index 67533ac9..7c3b7c21 100644 --- a/requirements.txt +++ b/requirements.txt @@ -38,3 +38,4 @@ streamlit-mic-recorder tinify cloudscraper xmlschema +googlesearch-python