From ca8618a6a4b9c5ab1be08722cd4620aae1504253 Mon Sep 17 00:00:00 2001 From: ajaysi Date: Wed, 4 Sep 2024 21:51:52 +0530 Subject: [PATCH] AI SEO tools - Readibility & Analysis, Agents content ideator --- README.md | 111 ++++--- alwrity.py | 22 +- lib/ai_seo_tools/TBD | 24 +- lib/ai_seo_tools/image_alt_text_generator.py | 19 ++ lib/ai_seo_tools/sitemap_analysis.py | 270 +++++++++++++++++ lib/ai_seo_tools/textstaty.py | 272 ++++++++++++++++++ lib/ai_seo_tools/webpage_content_analysis.py | 96 +++++++ lib/ai_seo_tools/weburl_seo_checker.py | 111 +++++++ lib/ai_seo_tools/wordcloud.py | 80 ++++++ lib/blog_postprocessing/blog_proof_reader.py | 81 ++++++ .../content_planning_agents_alwrity_crew.py | 2 +- lib/utils/.alwrity_utils.py.swp | Bin 45056 -> 0 bytes lib/utils/alwrity_utils.py | 37 ++- requirements.txt | 2 + 14 files changed, 1077 insertions(+), 50 deletions(-) create mode 100644 lib/ai_seo_tools/sitemap_analysis.py create mode 100644 lib/ai_seo_tools/textstaty.py create mode 100644 lib/ai_seo_tools/webpage_content_analysis.py create mode 100644 lib/ai_seo_tools/weburl_seo_checker.py create mode 100644 lib/ai_seo_tools/wordcloud.py delete mode 100644 lib/utils/.alwrity_utils.py.swp diff --git a/README.md b/README.md index 118b268a..e8c50836 100644 --- a/README.md +++ b/README.md @@ -71,53 +71,92 @@ Still stuck, [Open issue here](https://github.com/AJaySi/AI-Writer/issues) & Som --- -## ALwrity Features +## Alwrity Features: Power Up Your Content Creation Life cycle ⚑️ -| No. | Alwrity Tool | Description | -|-----|------------------------------------|--------------------------------------------------------------------------------| -| 1 | ![AI Blog Writer](https://www.alwrity.com/ai-blog-writer) | Generates blog content based on the latest web research on given keywords. | -| 2 | AI YouTube to Content Writer | Transforms content from provided YouTube URLs into written form. | -| 3 | AI Long Form Content | Creates extensive and detailed articles. | -| 4 | AI Essay Writer | Produces lengthy essays on various topics, with room for improvement. | -| 5 | AI Story Writer | Constructs narratives and stories based on provided backstories and characters.| -| 6 | AI Email Writer | Generates various types of professional letters. | -| 7 | AI Letter Writer | Crafts business letters for formal communication. | -| 8 | AI LinkedIn Blog Post Generator | Develops blog posts optimized for sharing on LinkedIn. | -| 9 | AI Instagram Caption Generation | Creates engaging captions for Instagram posts. | -| 10 | AI Content Outline Generator | Generates outlines based on keywords gathered from web research. | -| 11 | AI Web Researcher | Conducts comprehensive web research and analysis using various methods. | -| 12 | AI Content Planning & Calendar | Assists in planning and organizing content with a comprehensive calendar. | -| 13 | Create Blog Images | Generates images to complement blog content using Stable Diffusion. | -| 14 | Agentic Content Creation | Explores innovative content creation methods with CrewAI. | -| 15 | AI Finance Writer | Uses ufinance & padnas_ta to write TA report for given stock symbol | -| 16 | AI Agents Team | Easily create AI Agents team for Content creation & Digital marketing | -| 17 | Talk to your Docs (WIP) | Write content from your local documents of any type(multi-modal) | -| 18 | Wordpress API integration | Programmatically upload blogs to wordpress website with API keys | -| 19 | Talk to your website | Crawl Crawl your entire website & write content based on its content, Or Not | -| 20 | Content From URLs | Provide any URL to create an original, unique content from | -| 21 | SEO Structured Data | Feature: AI SEO - Generate rich snippet from url | +**AI Writer Tools:** -- **Online Research Integration**: Enhances blog content by integrating insights and information gathered from online research(SERP, Tavily, Metaphor), ensuring the content is informative and up-to-date. -This gives context for generating content. Reduces AI Hallucination. Tavily AI, Google search, serp and Vision AI is used to scrape web data for context augumentation. CrewAI for web research agents. +| Tool | Description | +|---------------------------------------|---------------------------------------------------------------------------| +| AI Blog Writer | Generates blog content based on the latest web research on given keywords. | +| AI YouTube to Content Writer | Transforms content from provided YouTube URLs into written form. | +| AI Long Form Content | Creates extensive and detailed articles. | +| AI Essay Writer | Produces lengthy essays on various topics, with room for improvement. | +| AI Story Writer | Constructs narratives and stories based on provided backstories and characters. | +| AI Email Writer | Generates various types of professional letters. | +| AI Letter Writer | Crafts business letters for formal communication. | +| AI LinkedIn Blog Post Generator | Develops blog posts optimized for sharing on LinkedIn. | +| AI Instagram Caption Generation | Creates engaging captions for Instagram posts. | +| AI Content Outline Generator | Generates outlines based on keywords gathered from web research. | -- **Long Form Content Generation**: Write Essay, Story, Long form Blogs with web researched context. +--- +**AI SEO Tools:** -- **AI Content planning & Calender**: Writer's block, Alwrity will provide you with months worth of blog titles. +| Tool | Description | +|---------------------------------------|---------------------------------------------------------------------------| +| AI Content Outline Generator | Generates outlines based on keywords gathered from web research. | +| AI SEO - Generate rich snippet from url | Creates structured data for rich snippets (e.g., reviews, recipes) | -- **Multilingual**: Write Content in your language, web research in your language and country(main_config). +**AI Content Planning Tools:** -- **Prevents AI Hallucinations**: Web researched context generates factual content. +| Tool | Description | +|---------------------------------------|---------------------------------------------------------------------------| +| AI Content Planning & Calendar | Assists in planning and organizing content with a comprehensive calendar. | +| Create Blog Images | Generates images to complement blog content using Stable Diffusion. | +| Agentic Content Creation | Explores innovative content creation methods with CrewAI. | +| AI Finance Writer | Uses ufinance & padnas_ta to write TA report for given stock symbol | -- **Text-To-Text, Speech-To-Text, Text-To-Image, Image-To-Text**: Multimodal content generatiom suite. +**AI Web Research Integrations:** -- **Agentic Content Team**: Crewai content team for you company. Define persona, roles, goals, task for your AI content team(Beta). +| Tool | Description | +|---------------------------------------|---------------------------------------------------------------------------| +| AI Web Researcher | Conducts comprehensive web research and analysis using various methods. | +| Talk to your Docs (WIP) | Write content from your local documents of any type (multi-modal) | -- **Image Generation and Processing**: Utilizes AI models like DALL-E 3, stable difffusion to create relevant images based on blog content. Offers features to process and optimize images for web usage. FIXME: Need more work with stable diffusion. +**Integrations:** -- **SEO Optimization**: Employs AI to generate SEO-friendly blog titles, meta descriptions, tags, and categories. Ensures content is optimized for search engines. +| Tool | Description | +|---------------------------------------|---------------------------------------------------------------------------| +| AI Agents Team | Easily create AI Agents team for Content creation & Digital marketing | +| Wordpress API integration | Programmatically upload blogs to wordpress website with API keys | +| Talk to your website | Crawl your entire website & write content based on its content, Or Not | +| Content From URLs | Provide any URL to create an original, unique content from | + +--- + +## Superpowers πŸš€ **🧠 Here's what Alwrity can do for you:** + +* **Online content Research:** πŸ” Supercharge your blog posts by integrating insights from online research (SERP, Tavily, Metaphor). Say goodbye to AI hallucinations! Tavily AI, Google Search, SERP, Vision AI, and CrewAI web research agents ensure your content is packed with accurate information. +* **Long Form Content Generation:** ✍️ Write essays, stories, and in-depth blogs with web-researched context. No more staring at a blank page! +* **AI Content Planning & Calendar:** πŸ—“οΈ Say goodbye to writer's block! Alwrity will give you months' worth of blog title ideas. + +**🌍 Multi-Language Magic:** + +* **Multilingual Support:** 🌎 Write content and conduct web research in your language. We support multiple languages and regions (main_config)! + +**🧠 Fighting AI Hallucinations:** + +* **Fact-Checked Content:** πŸ™… We use web-researched context to generate factual content, eliminating the risk of AI hallucinations. + +**🎨 Multimodal Content Mastery:** + +* **Text-To-Text, Speech-To-Text, Text-To-Image, Image-To-Text:** πŸ–ΌοΈ Our multimodal suite empowers you to create a variety of content formats. + +**πŸ€– Your Content Creation Crew:** + +* **Agentic Content Team:** 🀝 Build your own AI content team with CrewAI! Define their personas, roles, goals, and tasks. (Beta) + +**πŸ“Έ Visualize Your Content:** + +* **Image Generation and Processing:** ✨ Create stunning images based on your blog content using DALL-E 3 and Stable Diffusion. Optimize your images for web use. (FIXME: More Stable Diffusion magic to come!) + +**SEO Mastery:** + +* **SEO Optimization:** πŸ“ˆ Boost your content's visibility. Alwrity generates SEO-friendly titles, meta descriptions, tags, and categories. + +**πŸ€– Streamlined Content Publishing:** + +* **WordPress & Jekyll Integration:** πŸš€ Effortlessly generate and upload your content (and media!) to WordPress using its REST API. Most markdown-based static websites should integrate seamlessly with minimal effort. -- **Wordpress, Jekyll Integration**: Implemented generating and uploading blog content, media to wordpress via its REST APIs. Most of the static website which can work with markdown style should work with little testing. - --- > [!NOTE]

This toolkit is designed for automated blog management and requires appropriate API keys and access credentials for full functionality. ALwrity will guide your through this process, we selected APIs which offer generous free trials, **you** only need email id & patience.

diff --git a/alwrity.py b/alwrity.py index 648dd313..236045b2 100644 --- a/alwrity.py +++ b/alwrity.py @@ -16,6 +16,7 @@ from lib.utils.alwrity_utils import (blog_from_keyword, ai_agents_team, essay_wr 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 def check_api_keys(): @@ -325,12 +326,12 @@ def main(): if check_api_keys() and check_llm_environs(): # Define the tabs tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs( - ["βœοΈπŸ€–AI Writers", " πŸ“πŸ“…Content Planning", "πŸ€πŸ€–Agents Teams", "πŸ› οΈπŸ”AI SEO tools", "πŸ“±AI Social Tools", " πŸ’¬Ask Alwrity"]) + ["πŸ“…Content Planning", " πŸ“πŸ€–AI Writers", "πŸ€πŸ€–Agents Teams", "πŸ› οΈπŸ”AI SEO tools", "πŸ“±AI Social Tools", " πŸ’¬Ask Alwrity"]) with tab1: - ai_writers() + content_planning_tools() with tab2: - content_planning_tools() + ai_writers() with tab3: ai_agents_team() @@ -404,7 +405,7 @@ def content_planning_tools(): options = [ "Keywords Researcher", "Competitor Analysis", - "Get Content Calender" + "Content Calender Ideator" ] choice = st.radio("Select a content planning tool:", options, index=0, format_func=lambda x: f"πŸ” {x}") @@ -412,8 +413,17 @@ def content_planning_tools(): do_web_research() elif choice == "Competitor Analysis": competitor_analysis() - elif choice == "Get Content Calender": - planning_agents() + elif choice == "Content Calender Ideator": + plan_keywords = st.text_input( + "**Enter Your main Keywords to get 2 months content calendar:**", + placeholder="Enter 2-3 main keywords to generate AI content calendar with keyword researched blog titles", + help="The keywords are the ones where you would want to generate 50-60 blogs/articles on." + ) + if st.button("**Ideate Content Calender**"): + if plan_keywords: + ai_agents_content_planner(plan_keywords) + else: + st.error("Come on, really, Enter some keywords to plan on..") def alwrity_brain(): diff --git a/lib/ai_seo_tools/TBD b/lib/ai_seo_tools/TBD index 43abf61a..cbe6e3e2 100644 --- a/lib/ai_seo_tools/TBD +++ b/lib/ai_seo_tools/TBD @@ -1,4 +1,3 @@ -https://pypi.org/project/textstat/ https://github.com/greghub/website-launch-checklist https://github.com/marcobiedermann/search-engine-optimization https://developers.google.com/speed/docs/insights/v5/get-started @@ -11,3 +10,26 @@ https://github.com/dataforseo/PythonClient https://mysiteauditor.com/api https://github.com/searchsolved/search-solved-public-seo/blob/main/keyword-research/low-competition-keyword-finder-serp-api/low_competition_finder_serp_api.py + +### Structured Data + +- [Facebook Debugger](https://developers.facebook.com/tools/debug) - Enter the URL you want to scrape to see how the page's markup appears to Facebook. +- [Pinterest](https://developers.pinterest.com/rich_pins/validator/) - Validate your Rich Pins and apply to get them on Pinterest. +- [Structured Data Testing Tool](https://developers.google.com/structured-data/testing-tool/) - Paste in your rich snippets or url to test it. +- [Twitter card validator](https://cards-dev.twitter.com/validator) - Enter the URL of the page with the meta tags to validate. + +https://github.com/sethblack/python-seo-analyzer + +https://www.holisticseo.digital/python-seo/analyse-compare-robots-txt/ + +https://github.com/Nv7-GitHub/googlesearch +https://www.semrush.com/blog/python-for-google-search/ + +https://www.kaggle.com/code/eliasdabbas/botpresso-crawl-audit-analysis +https://www.kaggle.com/code/eliasdabbas/nike-xml-sitemap-audit-analysis +https://www.kaggle.com/code/eliasdabbas/twitter-user-account-analysis-python-sejournal +https://www.kaggle.com/code/eliasdabbas/seo-crawl-analysis-template +https://www.kaggle.com/code/eliasdabbas/advertools-seo-crawl-analysis-template + +https://www.semrush.com/blog/content-analysis-xml-sitemaps-python/ + diff --git a/lib/ai_seo_tools/image_alt_text_generator.py b/lib/ai_seo_tools/image_alt_text_generator.py index fbe97fe0..345d8ded 100644 --- a/lib/ai_seo_tools/image_alt_text_generator.py +++ b/lib/ai_seo_tools/image_alt_text_generator.py @@ -17,6 +17,25 @@ def get_image_description(image_path): "Content-Type": "application/json", "Authorization": f"Bearer {os.getenv('OPENAI_API_KEY')}" } + +# Understand which images are informative, decorative, functional, or complex. +# Identify informative images, then write the text alternative for images using the essential information, describing it in detail. +# Don’t forget to include the emotional implications of the image. +# Filter out decorative images, like a flourish or stylistic elements that lack meaningful context. +# Then, write the alt text as β€œnull” as in, ”” so that screen readers won’t waste users’ time by announcing it. +# Take your functional images, which describe what happens when you click an image, like the β€˜download’ icon. +# Then, make sure your alt text doesn’t describe those images but instead, denotes their functionality. +# Grab your complex infographics or diagrams, then compose alt text describing the information laid out in the images. +# +# Less is more: Ensure the length of alternative text is under 125 characters when possible, spaces included. +# Don’t skimp on quality: Pay close attention to the accuracy of the information and insight the image provides in that short amount of words. +# Don’t use images of text, whenever possible, except in logos. If used, the image alt text should include the same words as in the image. +# For image maps, with multiple clickable areas, a group alt text gives the overall context of the map. +# Any clickable area should also have its own individual alternative text, describing the link’s destination and purpose. +# Don’t ever assign a random, vague, or ambiguous alternative text description to an image simply to increase your accessibility score. +# This could lead to confusion and frustration for a screen reader user. +# Alt text accessibility is rooted in providing meaningful and functional alternative means of usability. +# Poor or random alt text descriptions can arguably be worse than having no alt text at all. payload = { "model": "gpt-4o-mini", diff --git a/lib/ai_seo_tools/sitemap_analysis.py b/lib/ai_seo_tools/sitemap_analysis.py new file mode 100644 index 00000000..854efd2a --- /dev/null +++ b/lib/ai_seo_tools/sitemap_analysis.py @@ -0,0 +1,270 @@ +import streamlit as st +import advertools as adv +import pandas as pd +import plotly.graph_objects as go +from urllib.error import URLError +import xml.etree.ElementTree as ET +import requests + +def main(): + st.title("πŸ“Š Sitemap Analyzer") + st.write(""" + This tool analyzes a website's sitemap to understand its content structure and publishing trends. + Enter a sitemap URL to start your analysis. + """) + + sitemap_url = st.text_input("Please enter the sitemap URL:", "https://www.example.com/sitemap.xml") + + if st.button("Analyze Sitemap"): + try: + sitemap_df = fetch_all_sitemaps(sitemap_url) + if sitemap_df is not None and not sitemap_df.empty: + sitemap_df = process_lastmod_column(sitemap_df) + ppmonth = analyze_content_trends(sitemap_df) + sitemap_df = categorize_and_shorten_sitemaps(sitemap_df) + + display_key_metrics(sitemap_df, ppmonth) + plot_sitemap_content_distribution(sitemap_df) + plot_content_trends(ppmonth) + plot_content_type_breakdown(sitemap_df) + plot_publishing_frequency(sitemap_df) + + st.success("πŸŽ‰ Analysis complete!") + else: + st.error("No valid URLs found in the sitemap.") + except URLError as e: + st.error(f"Error fetching the sitemap: {e}") + except Exception as e: + st.error(f"An unexpected error occurred: {e}") + +def fetch_all_sitemaps(sitemap_url): + st.write(f"πŸš€ Fetching and analyzing the sitemap: {sitemap_url}...") + + try: + sitemap_df = fetch_sitemap(sitemap_url) + + if sitemap_df is not None: + all_sitemaps = sitemap_df.loc[sitemap_df['loc'].str.contains('sitemap'), 'loc'].tolist() + + if all_sitemaps: + st.write(f"πŸ”„ Found {len(all_sitemaps)} additional sitemaps. Fetching data from them...") + all_urls_df = pd.DataFrame() + + for sitemap in all_sitemaps: + try: + st.write(f"Fetching URLs from {sitemap}...") + temp_df = fetch_sitemap(sitemap) + if temp_df is not None: + all_urls_df = pd.concat([all_urls_df, temp_df], ignore_index=True) + except Exception as e: + st.error(f"Error fetching {sitemap}: {e}") + + st.write(f"βœ… Successfully fetched {len(all_urls_df)} URLs from all sitemaps.") + return all_urls_df + + else: + st.write(f"βœ… Successfully fetched {len(sitemap_df)} URLs from the main sitemap.") + return sitemap_df + else: + return None + + except Exception as e: + st.error(f"⚠️ Error fetching the sitemap: {e}") + return None + +def fetch_sitemap(url): + try: + response = requests.get(url) + response.raise_for_status() + + ET.fromstring(response.content) + + sitemap_df = adv.sitemap_to_df(url) + return sitemap_df + + except requests.RequestException as e: + st.error(f"⚠️ Request error: {e}") + return None + except ET.ParseError as e: + st.error(f"⚠️ XML parsing error: {e}") + return None + +def process_lastmod_column(sitemap_df): + st.write("πŸ“… Converting 'lastmod' column to DateTime format and setting it as the index...") + + try: + sitemap_df = sitemap_df.dropna(subset=['lastmod']) + sitemap_df['lastmod'] = pd.to_datetime(sitemap_df['lastmod']) + sitemap_df.set_index('lastmod', inplace=True) + + st.write("βœ… 'lastmod' column successfully converted to DateTime format and set as the index.") + return sitemap_df + + except Exception as e: + st.error(f"⚠️ Error processing the 'lastmod' column: {e}") + return None + +def categorize_and_shorten_sitemaps(sitemap_df): + st.write("πŸ” Categorizing and shortening sitemap names...") + + try: + sitemap_df['sitemap_name'] = sitemap_df['sitemap'].str.split('/').str[4] + sitemap_df['sitemap_name'] = sitemap_df['sitemap_name'].replace({ + 'sitemap-site-kasko-fiyatlari.xml': 'Kasko', + 'sitemap-site-bireysel.xml': 'Personal', + 'sitemap-site-kurumsal.xml': 'Cooperate', + 'sitemap-site-arac-sigortasi.xml': 'Car', + 'sitemap-site.xml': 'Others' + }) + + st.write("βœ… Sitemap names categorized and shortened.") + return sitemap_df + + except Exception as e: + st.error(f"⚠️ Error categorizing sitemap names: {e}") + return sitemap_df + +def analyze_content_trends(sitemap_df): + st.write("πŸ“… Analyzing content publishing trends...") + + try: + ppmonth = sitemap_df.resample('M').size() + sitemap_df['monthly_count'] = sitemap_df.index.to_period('M').value_counts().sort_index() + + st.write("βœ… Content trends analysis completed.") + return ppmonth + + except Exception as e: + st.error(f"⚠️ Error during content trends analysis: {e}") + return pd.Series() + +def display_key_metrics(sitemap_df, ppmonth): + st.write("### Key Metrics") + + total_urls = len(sitemap_df) + total_articles = ppmonth.sum() + average_frequency = ppmonth.mean() + + st.write(f"**Total URLs Found:** {total_urls:,}") + st.write(f"**Total Articles Published:** {total_articles:,}") + st.write(f"**Average Monthly Publishing Frequency:** {average_frequency:.2f} articles/month") + +def plot_sitemap_content_distribution(sitemap_df): + st.write("πŸ“Š Visualizing content amount by sitemap categories...") + + try: + if 'sitemap_name' in sitemap_df.columns: + stmc = sitemap_df.groupby('sitemap_name').size() + fig = go.Figure() + fig.add_bar(x=stmc.index, y=stmc.values, name='Sitemap Categories') + fig.update_layout( + title='Content Amount by Sitemap Categories', + xaxis_title='Sitemap Categories', + yaxis_title='Number of Articles', + paper_bgcolor='#E5ECF6' + ) + st.plotly_chart(fig) + else: + st.warning("⚠️ The 'sitemap_name' column is missing in the data.") + + except Exception as e: + st.error(f"⚠️ Error during sitemap content distribution plotting: {e}") + +def plot_content_trends(ppmonth): + st.write("πŸ“ˆ Plotting content publishing trends over time...") + + try: + fig = go.Figure() + fig.add_scatter(x=ppmonth.index, y=ppmonth.values, mode='lines+markers', name='Publishing Trends') + fig.update_layout( + title='Content Publishing Trends Over Time', + xaxis_title='Month', + yaxis_title='Number of Articles', + paper_bgcolor='#E5ECF6' + ) + st.plotly_chart(fig) + + except Exception as e: + st.error(f"⚠️ Error during content trends plotting: {e}") + +def plot_content_type_breakdown(sitemap_df): + st.write("πŸ” Plotting content type breakdown...") + + try: + if 'sitemap_name' in sitemap_df.columns and not sitemap_df['sitemap_name'].empty: + content_type_counts = sitemap_df['sitemap_name'].value_counts() + st.write("Content Type Counts:", content_type_counts) # Debug line + + if not content_type_counts.empty: + fig = go.Figure(data=[go.Pie(labels=content_type_counts.index, values=content_type_counts.values)]) + fig.update_layout( + title='Content Type Breakdown', + paper_bgcolor='#E5ECF6' + ) + st.plotly_chart(fig) + else: + st.warning("⚠️ No content types to display.") + else: + st.warning("⚠️ The 'sitemap_name' column is missing or empty.") + + except Exception as e: + st.error(f"⚠️ Error during content type breakdown plotting: {e}") + +def visualize_content_by_sitemap_category(sitemap_df): + st.write("πŸ” Visualizing content amount by sitemap categories...") + + try: + # Check if the 'sitemap_name' column exists and is non-empty + if 'sitemap_name' in sitemap_df.columns and not sitemap_df['sitemap_name'].empty: + st.write("Sitemap Data Preview:", sitemap_df['sitemap_name'].head()) # Check the data + + # Group and count the number of entries per sitemap category + sitemap_category_counts = sitemap_df['sitemap_name'].value_counts() + + # Display the grouped data + st.write("Sitemap Category Counts:", sitemap_category_counts) # Debug line + + # If we have valid data, plot it + if not sitemap_category_counts.empty: + fig = go.Figure() + fig.add_bar(x=sitemap_category_counts.index, y=sitemap_category_counts.values, name='Sitemap Names') + fig.update_layout( + title='Content Amount by Sitemap Categories', + paper_bgcolor='#E5ECF6', + yaxis_title='Article Amount', + ) + st.plotly_chart(fig) + else: + st.warning("⚠️ No data to display for sitemap categories.") + else: + st.warning("⚠️ The 'sitemap_name' column is missing or empty.") + + except Exception as e: + st.error(f"⚠️ Error during content amount visualization: {e}") + +def plot_publishing_frequency(sitemap_df): + st.write("πŸ“† Plotting publishing frequency by month...") + + try: + if not sitemap_df.empty: + frequency_by_month = sitemap_df.index.to_period('M').value_counts().sort_index() + frequency_by_month.index = frequency_by_month.index.astype(str) # Convert Period to string for Plotly + + fig = go.Figure() + fig.add_bar(x=frequency_by_month.index, y=frequency_by_month.values, name='Publishing Frequency') + fig.update_layout( + title='Publishing Frequency by Month', + xaxis_title='Month', + yaxis_title='Number of Articles', + paper_bgcolor='#E5ECF6' + ) + st.plotly_chart(fig) + else: + st.warning("⚠️ No data available to plot publishing frequency.") + + except Exception as e: + st.error(f"⚠️ Error during publishing frequency plotting: {e}") + +if __name__ == "__main__": + main() + diff --git a/lib/ai_seo_tools/textstaty.py b/lib/ai_seo_tools/textstaty.py new file mode 100644 index 00000000..77e85416 --- /dev/null +++ b/lib/ai_seo_tools/textstaty.py @@ -0,0 +1,272 @@ +import textstat +import streamlit as st + +st.set_page_config(layout="wide", page_title="Text Readability Analyzer", page_icon=":book:") + +st.title("πŸ“– Text Readability Analyzer: Making Your Content Easy to Read") + +st.write(""" + This tool is your guide to writing content that's easy for your audience to understand. + Just paste in a sample of your text, and we'll break down the readability scores and offer actionable tips! +""") + +text_input = st.text_area("Paste your text here:", height=200) + +if st.button("Analyze!"): + with st.spinner("Analyzing your text..."): + test_data = text_input + + st.subheader("Readability Scores:") + st.write("---") + + # 1. Flesch Reading Ease + flesch_ease = textstat.flesch_reading_ease(test_data) + st.markdown(f"**Flesch Reading Ease:** {flesch_ease}") + st.markdown(""" + * **What It Means:** This score rates your text on a scale of 0-100, with higher scores being easier to read. Imagine a scale from "super confusing" (low scores) to "super easy" (high scores). + * **Actionable Tips:** + * **Score below 30?** It might be time to simplify. Break down complex sentences, use shorter words, and avoid jargon. + * **Score around 60-70?** You're in the "standard" range. + * **Score over 90?** Your text is very easy to read. But if you want to add some complexity or sophistication, try adding some longer sentences or slightly more complex vocabulary. + """) + + st.write(" ") + + # 2. Flesch-Kincaid Grade Level + flesch_kincaid = textstat.flesch_kincaid_grade(test_data) + st.markdown(f"**Flesch-Kincaid Grade Level:** {flesch_kincaid:.1f}") + st.markdown(""" + * **What It Means:** This formula estimates the US school grade level needed to understand your text. For example, a score of 7.2 means a 7th-grader should be able to understand it. + * **Actionable Tips:** + * **High Score?** If the grade level is much higher than your target audience's expected level, your writing might be too complex. + * **Low Score?** If the score is significantly lower, your audience might find the text too simple. + * **Match Your Audience:** Remember to tailor the complexity to your readers! + """) + + st.write(" ") + + # 3. SMOG Index + smog_index = textstat.smog_index(test_data) + st.markdown(f"**SMOG Index:** {smog_index:.1f}") + st.markdown(""" + * **What It Means:** This formula measures how complex your text is by looking at the number of long words and sentences. + * **Actionable Tips:** + * **Important Note:** This formula works best for texts with at least 30 sentences. + * **Adjust Complexity:** SMOG helps you determine whether your writing is appropriate for your target audience. + """) + + st.write(" ") + + # 4. Coleman-Liau Index + coleman_liau = textstat.coleman_liau_index(test_data) + st.markdown(f"**Coleman-Liau Index:** {coleman_liau:.1f}") + st.markdown(""" + * **What It Means:** This formula uses a more advanced method of analyzing sentence length and the number of syllables per word to estimate the reading level. + """) + + st.write(" ") + + # 5. Automated Readability Index (ARI) + ari = textstat.automated_readability_index(test_data) + st.markdown(f"**Automated Readability Index (ARI):** {ari:.1f}") + st.markdown(""" + * **What It Means:** Similar to other readability scores, the ARI estimates the grade level required to comprehend your text. + """) + + st.write(" ") + + # 6. Dale-Chall Readability Score + dale_chall = textstat.dale_chall_readability_score(test_data) + st.markdown(f"**Dale-Chall Readability Score:** {dale_chall:.1f}") + st.markdown(""" + * **What It Means:** This formula focuses on the number of uncommon words (not on a list of 3000 common words) and sentence length. + * **Actionable Tips:** + * **Easy to Understand:** Aim for a score around the reading level of your audience. If you're writing for a general audience, a score between 6 and 8 is usually considered good. + * **High School Level?** Scores between 9 and 12 usually indicate a high school reading level. + * **Beyond High School?** Scores above 12 are usually for a college-level audience. + """) + + st.write(" ") + + # 7. Gunning Fog + gunning_fog = textstat.gunning_fog(test_data) + st.markdown(f"**Gunning Fog:** {gunning_fog:.1f}") + st.markdown(""" + * **What It Means:** This formula calculates the grade level required to understand the text. + """) + + st.write(" ") + + # 8. Linsear Write Formula + linsear = textstat.linsear_write_formula(test_data) + st.markdown(f"**Linsear Write Formula:** {linsear:.1f}") + st.markdown(""" + * **What It Means:** This formula aims to estimate the US grade level needed to understand the text. + """) + + st.write(" ") + + # 9. Text Standard (Consensus) + text_standard = textstat.text_standard(test_data) + st.markdown(f"**Text Standard (Consensus):** {text_standard}") + st.markdown(""" + * **What It Means:** This score is a consensus estimate of the US grade level needed to understand your text. It's an average of all the readability scores. + """) + + st.write(" ") + + # 10. Spache Readability + spache = textstat.spache_readability(test_data) + st.markdown(f"**Spache Readability:** {spache:.1f}") + st.markdown(""" + * **What It Means:** This formula is best for analyzing text for children, typically up to grade 4. It considers the number of unfamiliar words and the length of sentences. + """) + + st.write(" ") + + # 11. McAlpine EFLAW + mcalpine = textstat.mcalpine_eflaw(test_data) + st.markdown(f"**McAlpine EFLAW:** {mcalpine:.1f}") + st.markdown(""" + * **What It Means:** This formula specifically evaluates text for foreign language learners (typically focusing on English). It looks at "miniwords" and sentence length. + * **Target Score:** Try to aim for a score of 25 or less. + """) + + st.write(" ") + + # --- Spanish Readability Formulas (For Examples, replace 'test_data' with your Spanish text)--- + + # 12. Fernandez-Huerta + # fernandez_huerta = textstat.fernandez_huerta(test_data) + # st.markdown(f"**Fernandez-Huerta (Spanish):** {fernandez_huerta:.1f}") + # st.markdown(""" + # * **Meaning:** This is an adaptation of the Flesch Reading Ease formula specifically for Spanish. + # * **Interpretation:** Higher scores mean easier readability. + # """) + + # st.write(" ") + + # 13. Szigriszt-Pazs (Spanish) + # szigriszt_pazos = textstat.szigriszt_pazos(test_data) + # st.markdown(f"**Szigriszt-Pazs (Spanish):** {szigriszt_pazos:.1f}") + # st.markdown(""" + # * **Meaning:** Another adaptation of the Flesch Reading Ease for Spanish text. It tries to measure the text's understandability. + # """) + + # st.write(" ") + + # 14. Gutierrez-Polini (Spanish) + # gutierrez_polini = textstat.gutierrez_polini(test_data) + # st.markdown(f"**Gutierrez-Polini (Spanish):** {gutierrez_polini:.1f}") + # st.markdown(""" + # * **Meaning:** Designed specifically for Spanish grade-school texts. + # * **Note:** The score may be unreliable for more complex text. + # """) + + # st.write(" ") + + # 15. Crawford (Spanish) + # crawford = textstat.crawford(test_data) + # st.markdown(f"**Crawford (Spanish):** {crawford:.1f}") + # st.markdown(""" + # * **Meaning:** This formula estimates the number of years of schooling needed to understand the text, primarily for elementary school-level Spanish. + # """) + + # st.write(" ") + + # --- Arabic Readability Formula (For Examples, replace 'test_data' with your Arabic text) --- + + # 16. Osman + # osman = textstat.osman(test_data) + # st.markdown(f"**Osman (Arabic):** {osman:.1f}") + # st.markdown(""" + # * **Meaning:** Designed for Arabic texts. An adaptation of Flesch and Fog formulas. + # """) + + # st.write(" ") + + # --- Italian Readability Formula --- + + # 17. Gulpease Index + # gulpease = textstat.gulpease_index(test_data) + # st.markdown(f"**Gulpease Index (Italian):** {gulpease:.1f}") + # st.markdown(""" + # * **Meaning:** Measures the readability of Italian text. + # * **Interpretation:** Lower scores require a higher level of education for ease of reading. + # """) + + # st.write(" ") + + # --- German Readability Formula (For Examples, replace 'test_data' with your German text) --- + + # 18. Wiener Sachtextformel + # wiener_sachtextformel = textstat.wiener_sachtextformel(test_data) + # st.markdown(f"**Wiener Sachtextformel (German):** {wiener_sachtextformel:.1f}") + # st.markdown(""" + # * **Meaning:** This formula measures the readability of German texts. + # * **Interpretation:** + # * 4: Very easy text + # * 15: Very difficult text + # """) + + # st.write(" ") + + st.subheader("Additional Insights:") + st.write("---") + + # 19. Reading Time + reading_time = textstat.reading_time(test_data) + st.markdown(f"**Estimated Reading Time:** {reading_time:.1f} minutes") + + st.write(" ") + + # 20. Syllable Count + syllable_count = textstat.syllable_count(test_data) + st.markdown(f"**Syllable Count:** {syllable_count}") + + st.write(" ") + + # 21. Lexicon Count (Word Count) + lexicon_count = textstat.lexicon_count(test_data) + st.markdown(f"**Word Count:** {lexicon_count}") + + st.write(" ") + + # 22. Sentence Count + sentence_count = textstat.sentence_count(test_data) + st.markdown(f"**Sentence Count:** {sentence_count}") + + st.write(" ") + + # 23. Character Count + char_count = textstat.char_count(test_data) + st.markdown(f"**Character Count:** {char_count}") + + st.write(" ") + + # 24. Letter Count + letter_count = textstat.letter_count(test_data) + st.markdown(f"**Letter Count (without punctuation):** {letter_count}") + + st.write(" ") + + # 25. Polysyllable Count + polysyllable_count = textstat.polysyllabcount(test_data) + st.markdown(f"**Polysyllable Count:** {polysyllable_count}") + + st.write(" ") + + # 26. Monosyllable Count + monosyllable_count = textstat.monosyllabcount(test_data) + st.markdown(f"**Monosyllable Count:** {monosyllable_count}") + + st.write(" ") + + st.subheader("Key Takeaways:") + st.write("---") + st.markdown(""" + * **Don't Be Afraid to Simplify!** Often, simpler language makes content more impactful and easier to digest. + * **Aim for a Reading Level Appropriate for Your Audience:** Consider the education level, background, and familiarity of your readers. + * **Use Short Sentences:** This makes your content more scannable and easier to read. + * **Write for Everyone:** Accessibility should always be a priority. When in doubt, aim for clear, concise language! + """) diff --git a/lib/ai_seo_tools/webpage_content_analysis.py b/lib/ai_seo_tools/webpage_content_analysis.py new file mode 100644 index 00000000..7e4663d7 --- /dev/null +++ b/lib/ai_seo_tools/webpage_content_analysis.py @@ -0,0 +1,96 @@ +import streamlit as st +import requests +from bs4 import BeautifulSoup +import pandas as pd +import nltk +from nltk.tokenize import word_tokenize +from nltk.util import ngrams +from langchain.llms import OpenAI +from langchain.chains import ConversationChain + +st.set_page_config(layout="wide", page_title="Web Content Analyzer - Dive Deep with AI!", page_icon=":mag_right:") + +st.title("🧠 Web Content Analyzer: Uncover Hidden Insights with AI! 🧠") +st.write(""" + Welcome! This tool leverages the power of AI to analyze your web page's content. It goes beyond just keywords - + we'll use cutting-edge technology to uncover valuable insights and unlock new ways to boost your website! + """) + +# --- User Input --- + +url_input = st.text_input("Paste your URL here:", "https://www.example.com/") +language_input = st.selectbox("What language is your content?", ('English', 'Italian', 'Albanian')) +st.write(" ") + +# --- AI Model Setup --- + +llm = OpenAI(temperature=0.7) +conversation_chain = ConversationChain(llm=llm) + +# --- Analyze Button & Processing --- + +if st.button("Analyze with AI!"): + with st.spinner('Analyzing your content...'): + url = url_input.strip() + language = language_input.lower() + + if not url.startswith("http"): + st.error("Oops! Looks like you forgot 'http://' or 'https://' at the beginning of your URL. Please add it and try again! 😊") + st.stop() + + try: + response = requests.get(url) + response.raise_for_status() + + soup = BeautifulSoup(response.content, 'html.parser') + body_txt = soup.find('body').text + + words = [w.lower() for w in word_tokenize(body_txt)] + stopw = nltk.corpus.stopwords.words(language) + + final_words = [w for w in words if w not in stopw and w.isalpha()] + + # Frequency analysis (same as before) + freq = nltk.FreqDist(final_words) + keywords = freq.most_common(10) + df_keywords = pd.DataFrame(keywords, columns=("Keyword", "Frequency")) + + # --- AI-Powered Insights --- + st.subheader("AI Insights:") + st.write(" ") + + st.markdown("**Main Theme:**") + ai_theme = conversation_chain.run(f"What is the main theme or topic of this content? \n {body_txt}") + st.markdown(f" {ai_theme}") + + st.write(" ") + + st.markdown("**Suggested Keywords:**") + ai_keywords = conversation_chain.run(f"What other relevant keywords might be helpful to target for this content? \n {body_txt}") + st.markdown(f" {ai_keywords}") + + st.write(" ") + + st.markdown("**Content Improvement:**") + ai_improvement = conversation_chain.run(f"What could be done to improve this content for clarity, engagement, or SEO? \n {body_txt}") + st.markdown(f" {ai_improvement}") + + # --- Display Frequency Results --- + st.write(" ") + + st.subheader("Top Keywords:") + st.write(" ") + st.dataframe(df_keywords) + + st.subheader("What's the Value of This AI Analysis?") + st.write(" ") + + st.markdown(""" + * **Uncover Hidden Insights:** AI can analyze your content in much more nuanced ways, helping you spot connections and trends you might have missed. + * **Go Beyond Keywords:** AI can provide in-depth insights into your content's main themes, tone, and even suggest relevant topics to explore further. + * **AI as a Partner:** Think of this AI as your content strategist, offering guidance and actionable steps to make your content even better. + + Ready to leverage the power of AI to optimize your content? Start putting the suggestions and insights you just received into practice. See what difference AI can make in your writing! πŸš€ + """) + except requests.exceptions.RequestException as e: + st.error(f"Oops! Something went wrong fetching the URL. Error: {e}") diff --git a/lib/ai_seo_tools/weburl_seo_checker.py b/lib/ai_seo_tools/weburl_seo_checker.py new file mode 100644 index 00000000..dca1a72a --- /dev/null +++ b/lib/ai_seo_tools/weburl_seo_checker.py @@ -0,0 +1,111 @@ +import streamlit as st +from urllib.parse import urlparse + + +# Title and introduction +def show_title_and_intro(): + st.title("🌟 URL SEO Checkup: Your Link's Health Report 🌟") + st.write(""" + Welcome to the URL SEO Checkup! This tool is like a doctor for your website links. + Just paste your URL, and we'll check if it's healthy and ready to climb the search engine ladder. + """) + + +# Basic HTTPS Check +def check_https(url): + st.subheader("The Basics - Are We Looking Good?") + st.write("---") + + if url.startswith("https://"): + st.success("✨ You're using HTTPS! This adds extra security, and Google rewards that with better rankings. Keep it up! ✨") + else: + st.warning("🚧 Heads Up! Your URL doesn't use 'https://'. This is a red flag for Google.") + st.info("πŸ”§ **How to fix:** Contact your hosting provider or website developer to install an SSL certificate. This will secure your site with HTTPS.") + + +# URL Length Check +def check_url_length(path): + st.subheader("The Length Test - Keep it Short and Sweet!") + st.write("---") + + if len(path) <= 50: + st.success("πŸ† Great! Your URL is short and user-friendly. Google loves short URLs! πŸ†") + else: + st.warning("🧭 Tip: Try shortening your URL. Shorter URLs are easier to remember and better for SEO.") + st.info("πŸ”§ **How to fix:** Consider removing unnecessary words or folders in the URL. Aim for concise, descriptive URLs that are easy for users to read.") + + +# Hyphen Check +def check_hyphens(path): + st.subheader("The Hyphen Check - Use Hyphens for Clear Separation!") + st.write("---") + + if "-" in path: + st.success("😎 You're on the right track! Using hyphens makes your URL more readable for both users and Google. 😎") + else: + st.warning("❓ Did you know? Using hyphens between words (like 'shoes-for-sale') helps Google understand your URL better!") + st.info("πŸ”§ **How to fix:** Update your URL to use hyphens (-) instead of spaces or underscores (_). For example, 'shoes-for-sale' instead of 'shoes_for_sale'.") + + +# File Extension Check +def check_file_extension(path): + st.subheader("File Extension Check - Showing Your Files With Pride!") + st.write("---") + + if "." in path: + st.success("πŸ₯³ File Extension Check: Your URL includes a file extension like '.html', which helps Google categorize your page. Nice job! πŸ₯³") + else: + st.warning("πŸ€” Your URL seems to be missing a file extension like '.html' or '.php'.") + st.info("πŸ”§ **How to fix:** While file extensions are not always required, adding them to static pages (like .html or .php) can improve clarity for search engines.") + + +# Keyword Insights +def show_keyword_insights(netloc, path): + st.subheader("Bonus Insight - Let's Talk Keywords") + st.write("---") + + st.info("Keywords are the words people use to search for information online. Your goal is to help Google understand what your page is about by using the right keywords in your URL!") + + st.markdown(f""" + **Your Domain:** {netloc} + **Your URL Path:** {path} + + **Suggestion:** Consider adding a primary keyword to your URL if it aligns with your page content. But don't overdo it – too many keywords can hurt your SEO. Keep it natural! + """) + + +# Main function to run the analysis +def run_analysis(url): + # Parse the URL + parsed_url = urlparse(url) + netloc = parsed_url.netloc # Domain name + path = parsed_url.path # Path after the domain + + # Run checks + check_https(url) + check_url_length(path) + check_hyphens(path) + check_file_extension(path) + show_keyword_insights(netloc, path) + + +# Display the app +def url_seo_checker(): + show_title_and_intro() + + # User input for URL + url_input = st.text_input("Paste your URL here:", "https://www.example.com/") + st.write(" ") # Add spacing + + # When the analyze button is clicked + if st.button("Let's Analyze!"): + with st.spinner('Checking your link...'): + url = url_input.strip() # Clean up the input + + # Validate URL format + if not url.startswith(("http://", "https://")): + st.error("Oops! It seems like your URL needs 'http://' or 'https://' at the beginning. Please add it!") + st.stop() + + # Run the analysis + run_analysis(url) diff --git a/lib/ai_seo_tools/wordcloud.py b/lib/ai_seo_tools/wordcloud.py new file mode 100644 index 00000000..76509e4e --- /dev/null +++ b/lib/ai_seo_tools/wordcloud.py @@ -0,0 +1,80 @@ +import streamlit as st +import requests +from bs4 import BeautifulSoup +import pandas as pd +import nltk +from nltk.tokenize import word_tokenize +from nltk.util import ngrams + +st.set_page_config(layout="wide", page_title="Web Content Analyzer - Dive Into Your Words!", page_icon=":mag:") + +st.title("πŸ”Ž Web Content Analyzer: Uncover Your Words' Power! πŸ”Ž") +st.write(""" + Welcome! This tool helps you understand the words that drive your website content. Just paste in your web page's + URL, and we'll give you insights you can use to improve your content and reach more people! + """) + +url_input = st.text_input("Paste your URL here:", "https://www.example.com/") +language_input = st.selectbox("What language is your content?", ('English', 'Italian', 'Albanian')) +num_results_input = st.slider("How many top words/phrases should we show?", min_value=10, max_value=150, value=50) +st.write(" ") + +if st.button("Analyze Your Content!"): + with st.spinner('Analyzing your content...'): + url = url_input.strip() + language = language_input.lower() + num_results = num_results_input + + if not url.startswith("http"): + st.error("Oops! Looks like you forgot 'http://' or 'https://' at the beginning of your URL. Please add it and try again! 😊") + st.stop() + + try: + response = requests.get(url) + response.raise_for_status() # Check for errors + + soup = BeautifulSoup(response.content, 'html.parser') + body_txt = soup.find('body').text + + words = [w.lower() for w in word_tokenize(body_txt)] + stopw = nltk.corpus.stopwords.words(language) + + final_words = [w for w in words if w not in stopw and w.isalpha()] + + # Frequency analysis + freq = nltk.FreqDist(final_words) + keywords = freq.most_common(num_results) + + bigrams = ngrams(final_words, 2) + freq_bigrams = nltk.FreqDist(bigrams) + bigrams_freq = freq_bigrams.most_common(num_results) + + # Create DataFrames for Display + df_keywords = pd.DataFrame(keywords, columns=("Keyword", "Frequency")) + df_bigrams = pd.DataFrame(bigrams_freq, columns=("Bigram", "Frequency")) + + st.subheader("Top Keywords and Phrases:") + st.write(" ") + st.dataframe(df_keywords) + + st.write(" ") + + st.subheader("Top Two-Word Phrases:") + st.write(" ") + st.dataframe(df_bigrams) + + st.write(" ") + st.subheader("What's the Value of This Analysis?") + st.write(" ") + + st.markdown(""" + * **See What Resonates:** Discover the most popular words and phrases used on your website. This can reveal themes and topics that your audience is interested in. + * **Find Keywords for SEO:** The analysis helps identify relevant keywords you could use for your website content and marketing efforts. + * **Improve Your Content:** You can understand how people might search for similar content and ensure you're providing the right keywords. + * **Stand Out:** Compare your results to other websites or competitors to understand how you can differentiate your content. + + Ready to dive deeper into your content's vocabulary? Start by making some of the keywords you just discovered the stars of your next blog post or social media message. You might be surprised at the impact! πŸš€ + """) + + except requests.exceptions.RequestException as e: + st.error(f"Oops! Something went wrong fetching the URL. Error: {e}") diff --git a/lib/blog_postprocessing/blog_proof_reader.py b/lib/blog_postprocessing/blog_proof_reader.py index 14277e6f..6130a89f 100644 --- a/lib/blog_postprocessing/blog_proof_reader.py +++ b/lib/blog_postprocessing/blog_proof_reader.py @@ -37,3 +37,84 @@ def blog_proof_editor(blog_content): return response except Exception as err: logger.error(f"Error Blog Proof Reading: {err}") + +import streamlit as st +import requests +from bs4 import BeautifulSoup +import pandas as pd +import nltk +from nltk.tokenize import word_tokenize +from nltk.util import ngrams +from langchain.llms import OpenAI +from langchain.chains import ConversationChain + +# ... (rest of your code) + + if st.button("Analyze with AI!"): + # ... (fetch and process content as before) + + with st.spinner('Analyzing your content...'): + st.subheader("AI Insights:") + st.write(" ") + + # 1. Overall Critique + st.markdown("**Overall Evaluation:**") + ai_overall = conversation_chain.run(f"""Analyze the provided article and give a constructive critique, focusing on its strengths and weaknesses regarding: + * Informativeness: Does it offer valuable information the reader might not know, or strengthen their understanding? + * Authority: Does the author demonstrate expertise and credibility, backing up claims with evidence? + * Captivatingness: Does it effectively engage the reader, capture attention, and make them want to continue reading? + + Provide specific examples to support your evaluation. + """) + st.markdown(f" {ai_overall}") + st.write(" ") + + # 2. Structure & Organization + st.markdown("**Structure and Organization:**") + ai_structure = conversation_chain.run(f"""Analyze the structure and organization of the provided article. + * Does it flow logically, with a clear beginning, middle, and end? + * Are subheadings effectively used to break down the content and guide the reader? + * Is the writing style consistent throughout the article? + + Suggest improvements for clarity and readability. + """) + st.markdown(f" {ai_structure}") + st.write(" ") + + # 3. Content Quality + st.markdown("**Content Quality:**") + ai_content = conversation_chain.run(f"""Critique the content of the article, considering: + * Is the value of the article clear? + * Does it address a pain point or a need for the target audience? + * Are the arguments compelling and supported by evidence or examples? + * Are any technical terms explained well? + + Identify areas where the content could be strengthened or improved. + """) + st.markdown(f" {ai_content}") + st.write(" ") + + # 4. Call to Action & Headline + st.markdown("**Headline and Call to Action:**") + ai_headline = conversation_chain.run(f"""Evaluate the effectiveness of the headline and call to action (CTA) in the provided article. + * Does the headline accurately and compellingly summarize the article's content? + * Is the CTA clear, actionable, and positioned well within the text? + + Provide suggestions for improving the headline and CTA. + """) + st.markdown(f" {ai_headline}") + st.write(" ") + + # 5. Writing Style & Tone + st.markdown("**Writing Style and Tone:**") + ai_style = conversation_chain.run(f"""Assess the overall writing style and tone of the article. + * Does it use jargon or overly technical language that might be inaccessible to the target audience? + * Is the tone appropriate for the topic and target audience (e.g., professional, conversational, humorous)? + * Is the writing clear, concise, and engaging? + + Suggest ways to improve the writing style and make the article more accessible and compelling for the intended reader. + """) + st.markdown(f" {ai_style}") + + # --- Display Keyword Results (same as before) --- + # ... (rest of your code) diff --git a/lib/content_planning_calender/content_planning_agents_alwrity_crew.py b/lib/content_planning_calender/content_planning_agents_alwrity_crew.py index b808822f..2cc7f8d6 100644 --- a/lib/content_planning_calender/content_planning_agents_alwrity_crew.py +++ b/lib/content_planning_calender/content_planning_agents_alwrity_crew.py @@ -220,7 +220,7 @@ def execute_tasks(agents, tasks): print(err) -def ai_agents_planner(search_keywords): +def ai_agents_content_planner(search_keywords): already_written_on = os.path.join(os.getcwd(), "lib", "content_planning_calender", "content_already_planned.txt") do_google_trends_analysis(search_keywords) result = None diff --git a/lib/utils/.alwrity_utils.py.swp b/lib/utils/.alwrity_utils.py.swp deleted file mode 100644 index 1337953b9081125f3231e885d0cf1aea8632215b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45056 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 VQZ8UD<)zDN+m_`zH(U^1{vW4TmC^tJ diff --git a/lib/utils/alwrity_utils.py b/lib/utils/alwrity_utils.py index 81148e08..c9b336b9 100644 --- a/lib/utils/alwrity_utils.py +++ b/lib/utils/alwrity_utils.py @@ -45,9 +45,10 @@ 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.on_page_seo_analyzer import analyze_onpage_seo +from lib.ai_seo_tools.weburl_seo_checker import url_seo_checker from lib.gpt_providers.text_to_image_generation.main_generate_image_from_prompt import generate_image -from lib.content_planning_calender.content_planning_agents_alwrity_crew import ai_agents_planner +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 @@ -133,7 +134,8 @@ def ai_seo_tools(): "Generate OpenGraph Tags", "Optimize/Resize Image", "Run Google PageSpeed Insights", - "Analyze On Page SEO" + "Analyze On Page SEO", + "URL SEO Checker" ] # Using st.radio instead of st.selectbox @@ -156,12 +158,13 @@ def ai_seo_tools(): 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.title("Blog Content Writer") + st.header("Blog Content Writer") col1, col2, col3 = st.columns([2, 1.5, 0.5]) with col1: user_input = st.text_area('**πŸ‘‡Enter Keywords/Title/YouTube Link/Web URLs**', @@ -193,6 +196,28 @@ def blog_from_keyword(): temp_file_path = temp_file.name content_type = st.radio("**πŸ‘‡Select content type:**", ["Normal-length content", "Long-form content", "Experimental - AI Agents team"]) + + # Add an expandable section for advanced writing options + with st.expander("Advanced Writing Options", expanded=False): + # Option 1: Select content type + content_type = st.radio("**πŸ‘‡ Select content type:**", + ["Normal-length content", "Long-form content", "Experimental - AI Agents team"]) + + # Option 2: Checkbox for 'Create SEO tags' (Checked by default) + create_seo_tags = st.checkbox('Create SEO tags', value=True, + help='Generate json-ld schema, Twitter, and Facebook tags.') + + # Option 3: Checkbox for 'Generate Social Media content' (Unchecked by default) + generate_social_media = st.checkbox('Generate Social Media content', value=False, + help="Write Facebook, Instagram posts & tweets for generated blog. Needed for marketing your blogs.") + + # Option 4: Checkbox for 'Do Content Analysis & Critique' (Unchecked by default) + content_analysis = st.checkbox('Do Content Analysis & Critique', value=False, + help="Blog Proof reading, Critique generated blog. Provide actionable changes & Editing options.") + + # Display a message at the bottom for user guidance + st.info("🚨 Make sure to personalize content from the sidebar. Important.") + if st.button("Write Blog"): # Clear the previous results from the screen st.empty() @@ -350,7 +375,7 @@ def ai_agents_team(): if plan_keywords and len(plan_keywords.split()) >= 2: with st.spinner("Get Content Plan..."): try: - plan_content = ai_agents_planner(plan_keywords) + plan_content = ai_agents_content_planner(plan_keywords) st.success(f"Successfully generated content plan for: {plan_keywords}") st.markdown(plan_content) except Exception as err: diff --git a/requirements.txt b/requirements.txt index 3154a19a..66fb5831 100644 --- a/requirements.txt +++ b/requirements.txt @@ -37,3 +37,5 @@ gTTS streamlit-mic-recorder tinify cloudscraper +xmlschema +advetools