diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..c20efe30 --- /dev/null +++ b/.gitignore @@ -0,0 +1,58 @@ +*cpython* +*.cpython* +.DS_Store +.vscode +*.pyc +.env +.env.local +.env.development.local +.env.test.local +pycache +__pycache__ +*.pyc +*.pyo +*.pyd +*.pyw +*.pyz +*.pywz +*.pyzw +*.pyzp +*.pywp +*.pywpz +*.pywpzp + +.swp +.swo +.swn +.swnw +.swnwp +.swnwpz +.swnwpzp + +*.log +*.log.* +*.log.*.* +*.log.*.*.* +*.log.*.*.*.* +*.log.*.*.*.*.* + +.venv +*.cpython* +*.cpython-312.pyc + +*venv +*.venv +*.venv* +*.venv_* +*.venv_*_* +*.venv_*_*_* +*.venv_*_*_*_* + +*venv +venv_new* +venv_* + +AI-Writer_cursor_workspace.code-workspace +*.code-workspace +.cursorignore +lib/ai_writers/__pycache__/ai_agents_crew_writer.cpython-312.pyc diff --git a/README.md b/README.md index 741d9974..a44e0919 100644 --- a/README.md +++ b/README.md @@ -284,3 +284,171 @@ Still stuck, [Open issue here](https://github.com/AJaySi/AI-Writer/issues) & Som > SOFTWARE. >
+## Easy Installation Guide for Content Creators + +### Step 1: Install Python 3.11 +1. Download Python 3.11 installer: + - Visit [Python 3.11.6 Download Page](https://www.python.org/downloads/release/python-3116/) + - Scroll down and click on "Windows installer (64-bit)" + - Save the file to your computer + +2. Run the installer: + - Double click the downloaded file + - โ IMPORTANT: Check "Add Python 3.11 to PATH" + - Click "Install Now" + - Wait for installation to complete + - Click "Close" + +### Step 2: Install ALwrity +1. Download this project: + - Click the green "Code" button above + - Select "Download ZIP" + - Extract the ZIP file to your desired location + +2. Open Command Prompt: + - Press Windows + R + - Type "cmd" and press Enter + - Navigate to the extracted folder: + ``` + cd path\to\ALwrity + ``` + +3. Run the automatic installer: + ``` + python setup.py install + ``` + +### Troubleshooting +If you encounter any issues: +1. Make sure Python 3.11 is installed correctly: + - Open Command Prompt + - Type: `python --version` + - Should show: `Python 3.11.x` + +2. Common Issues: + - If you see "Python is not recognized": Restart your computer + - If you get package errors: Run `pip install --upgrade pip` first + +Need help? [Open an issue](../../issues) and we'll assist you! + +## For Developers +If you're a developer or want to contribute: +```bash +# Clone the repository +git clone https://github.com/yourusername/ALwrity.git + +# Create virtual environment +python -m venv venv + +# Activate virtual environment +# On Windows: +.\venv\Scripts\activate +# On Mac/Linux: +source venv/bin/activate + +# Install dependencies +pip install -r requirements.txt +``` + +# ALwrity - AI Content Writing Assistant + +## Quick Start Guide for Non-Technical Users + +### Option 1: One-Click Installation (Recommended) +1. Download this project: + - Click the green "Code" button above + - Select "Download ZIP" + - Extract the ZIP file to your desired location (e.g., Desktop) + +2. Run the installer: + - Double-click `install.bat` in the extracted folder + - If Windows asks for permission, click "Yes" + - Follow the on-screen instructions + - Wait for the installation to complete + +3. Start ALwrity: + - Open Command Prompt (Windows + R, type "cmd", press Enter) + - Navigate to the ALwrity folder: + ``` + cd path\to\ALwrity + ``` + - Type `alwrity` and press Enter + +### Option 2: Manual Installation +If the one-click installer doesn't work, follow these steps: + +1. Install Python 3.11: + - Visit [Python 3.11.6 Download Page](https://www.python.org/downloads/release/python-3116/) + - Click "Windows installer (64-bit)" + - Run the installer + - โ IMPORTANT: Check "Add Python 3.11 to PATH" + - Click "Install Now" + - Wait for installation to complete + +2. Install ALwrity: + - Open Command Prompt (Windows + R, type "cmd", press Enter) + - Navigate to the ALwrity folder: + ``` + cd path\to\ALwrity + ``` + - Run the installation: + ``` + python setup.py install + ``` + - Follow any on-screen instructions + +3. Start ALwrity: + - In the same Command Prompt window, type: + ``` + alwrity + ``` + - Press Enter + +### Troubleshooting Guide + +#### Common Issues and Solutions: + +1. "Python is not recognized" + - Solution: Restart your computer after installing Python + - Make sure you checked "Add Python 3.11 to PATH" during installation + +2. "Visual C++ Build Tools not found" + - Solution: Run this command in an administrative PowerShell: + ``` + winget install Microsoft.VisualStudio.2022.BuildTools --silent --override "--wait --quiet --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended" + ``` + +3. "Rust compiler not found" + - Solution: Run these commands in PowerShell: + ``` + Invoke-WebRequest -Uri https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe -OutFile rustup-init.exe + ./rustup-init.exe -y + ``` + +4. Installation Errors + - Check the `install_errors.log` file in the ALwrity folder + - Share the error message with our support team + +#### Need Help? +- Open an issue on GitHub +- Join our support community +- Contact our support team + +### System Requirements +- Windows 10 or later +- Python 3.11.x +- At least 4GB RAM +- 2GB free disk space + +### First-Time Setup +After installation: +1. The first time you run ALwrity, it will ask for your API keys +2. Follow the on-screen instructions to enter your keys +3. Your keys will be saved securely for future use + +### Updating ALwrity +To update to the latest version: +1. Download the latest release +2. Run `install.bat` again +3. Follow the on-screen instructions + diff --git a/alwrity.py b/alwrity.py index 5048eafa..b6ffb3fd 100644 --- a/alwrity.py +++ b/alwrity.py @@ -1,24 +1,66 @@ import streamlit as st + +# Set page config - must be the first Streamlit command +st.set_page_config( + page_title="AI Writer - Content Generation Platform", + page_icon="โ๏ธ", + layout="wide", + initial_sidebar_state="collapsed", # Start with collapsed sidebar + menu_items={ + 'Get Help': None, + 'Report a bug': None, + 'About': None + } +) + +# Add CSS to hide sidebar during setup +st.markdown(""" + +""", unsafe_allow_html=True) + import os import json import base64 +import logging from datetime import datetime +# Configure logging +logging.basicConfig( + level=logging.DEBUG, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', + handlers=[ + logging.StreamHandler(), # Output to console + #logging.FileHandler('alwrity.log') # Output to file + ] +) +logger = logging.getLogger(__name__) + from lib.utils.config_manager import save_config from lib.utils.ui_setup import setup_ui -from lib.utils.api_key_manager import check_all_api_keys +from lib.utils.alwrity_sidebar import sidebar_configuration +from lib.utils.api_key_manager.api_key_manager import APIKeyManager, render +from lib.utils.api_key_manager.validation import check_all_api_keys from dotenv import load_dotenv -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.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 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 - - def process_folder_for_rag(folder_path): """Placeholder for the process_folder_for_rag function.""" + logger.info(f"Processing folder for RAG: {folder_path}") st.write(f"This is a placeholder for processing the folder: {folder_path}") @@ -27,225 +69,77 @@ def save_config(config): Saves the provided configuration dictionary to a JSON file specified by the environment variable. """ try: + logger.debug(f"Saving configuration to {os.getenv('ALWRITY_CONFIG')}") with open(os.getenv("ALWRITY_CONFIG"), "w") as config_file: json.dump(config, config_file, indent=4) + logger.info("Configuration saved successfully") except Exception as e: + logger.error(f"Error saving configuration: {str(e)}", exc_info=True) st.error(f"An error occurred while saving the configuration: {e}") -# Sidebar configuration -def sidebar_configuration(): - st.sidebar.title("๐ ๏ธ Personalization & Settings ๐๏ธ") - - with st.sidebar.expander("**๐ท Content Personalization**"): - blog_length = st.text_input("**Content Length (words)**", value="2000", - help="Approximate word count for blogs. Note: Actual length may vary based on GPT provider and max token count.") - - blog_tone_options = ["Casual", "Professional", "How-to", "Beginner", "Research", "Programming", "Social Media", "Customize"] - blog_tone = st.selectbox("**Content Tone**", - options=blog_tone_options, - help="Select the desired tone for the blog content.") - - if blog_tone == "Customize": - custom_tone = st.text_input("Enter the tone of your content", help="Specify the tone of your content.") - if custom_tone: - blog_tone = custom_tone - else: - st.warning("Please specify the tone of your content.") - - blog_demographic_options = ["Professional", "Gen-Z", "Tech-savvy", "Student", "Digital Marketing", "Customize"] - - blog_demographic = st.selectbox("**Target Audience**", - options=blog_demographic_options, - help="Select the primary audience for the blog content.") - if blog_demographic == "Customize": - custom_demographic = st.text_input("Enter your target audience", - help="Specify your target audience.", - placeholder="Eg. Domain expert, Content creator, Financial expert etc..") - if custom_demographic: - blog_demographic = custom_demographic - else: - st.warning("Please specify your target audience.") - - blog_type = st.selectbox("**Content Type**", - options=["Informational", "Commercial", "Company", "News", "Finance", "Competitor", "Programming", "Scholar"], - help="Select the category that best describes the blog content.") - - blog_language = st.selectbox("**Content Language**", - options=["English", "Spanish", "German", "Chinese", "Arabic", "Nepali", "Hindi", "Hindustani", "Customize"], - help="Select the language in which the blog will be written.") - if blog_language == "Customize": - custom_lang = st.text_input("Enter the language of your choice", help="Specify the content language.") - if custom_lang: - blog_language = custom_lang - else: - st.warning("Please specify the language of your content.") - - blog_output_format = st.selectbox("**Content Output Format**", - options=["markdown", "HTML", "plaintext"], - help="Select the format for the blog output.") - - with st.sidebar.expander("**๐ฉป Images Personalization**"): - image_generation_model = st.selectbox("**Image Generation Model**", - options=["stable-diffusion", "dalle2", "dalle3"], - help="Select the model to generate images for the blog.") - number_of_blog_images = st.number_input("**Number of Blog Images**", value=1, help="Specify the number of images to include in the blog.") - - with st.sidebar.expander("**๐ค LLM Personalization**"): - gpt_provider = st.selectbox("**GPT Provider**", - options=["google", "openai", "minstral"], - help="Select the provider for the GPT model.") - model = st.text_input("**Model**", value="gemini-1.5-flash-latest", help="Specify the model version to use from the selected provider.") - temperature = st.slider( - "Temperature", - min_value=0.1, - max_value=1.0, - value=0.7, - step=0.1, - format="%.1f", - help="""Temperature controls the 'creativity' or randomness of the text generated by GPT. - Greater determinism with higher values indicating more randomness.""" - ) - - top_p = st.slider( - "Top-p", - min_value=0.0, - max_value=1.0, - value=0.9, - step=0.1, - format="%.1f", - help="Top-p sampling controls the level of diversity in the generated text." - ) - - # Selectbox for max tokens - max_tokens_options = [500, 1000, 2000, 4000, 16000, 32000, 64000] - max_tokens = st.selectbox( - "Max Tokens", - options=max_tokens_options, - index=max_tokens_options.index(4000), - help="Max tokens determine the maximum length of the output sequence generated by a model." - ) - n = st.number_input("N", - value=1, - min_value=1, - max_value=10, - help="Defines the number of words or characters grouped together in a sequence when analyzing text.") - frequency_penalty = st.slider( - "Frequency Penalty", - min_value=0.0, - max_value=2.0, - value=1.0, - step=0.1, - format="%.1f", - help="Influences word selection during text generation, promoting diversity with higher values." - ) - - presence_penalty = st.slider( - "Presence Penalty", - min_value=0.0, - max_value=2.0, - value=1.0, - step=0.1, - format="%.1f", - help="Encourages the use of diverse words by discouraging repetition." - ) - - with st.sidebar.expander("**๐ต๏ธ Search Engine Personalization**"): - geographic_location = st.selectbox("**Geographic Location**", - options=["us", "in", "fr", "cn"], - help="Select the geographic location for tailoring search results.") - search_language = st.selectbox("**Search Language**", - options=["en", "zn-cn", "de", "hi"], - help="Select the language for the search results.") - number_of_results = st.number_input("**Number of Results**", - value=10, - max_value=20, - min_value=1, - help="Specify the number of search results to retrieve.") - time_range = st.selectbox("**Time Range**", - options=["anytime", "past day", "past week", "past month", "past year"], - help="Select the time range for filtering search results.") - include_domains = st.text_input("**Include Domains**", value="", - help="List specific domains to include in search results. Leave blank to include all domains.") - similar_url = st.text_input("**Similar URL**", value="", help="Provide a URL to find similar results. Leave blank if not needed.") - - # Storing collected inputs in a dictionary - config = { - "Blog Content Characteristics": { - "Blog Length": blog_length, - "Blog Tone": blog_tone, - "Blog Demographic": blog_demographic, - "Blog Type": blog_type, - "Blog Language": blog_language, - "Blog Output Format": blog_output_format - }, - "Blog Images Details": { - "Image Generation Model": image_generation_model, - "Number of Blog Images": number_of_blog_images - }, - "LLM Options": { - "GPT Provider": gpt_provider, - "Model": model, - "Temperature": temperature, - "Top-p": top_p, - "Max Tokens": max_tokens, - "N": n, - "Frequency Penalty": frequency_penalty, - "Presence Penalty": presence_penalty - }, - "Search Engine Parameters": { - "Geographic Location": geographic_location, - "Search Language": search_language, - "Number of Results": number_of_results, - "Time Range": time_range, - "Include Domains": include_domains, - "Similar URL": similar_url - } - } - - # Writing the configuration to a file whenever a change is made - save_config(config) - - - def main(): + """Main application entry point.""" + # Initialize API key manager + api_key_manager = APIKeyManager() + + # Setup UI + setup_ui() #load_environment load_dotenv() - setup_ui() - - if check_all_api_keys(): + logger.debug("Environment variables loaded") + setup_environment_paths() + logger.debug("Environment paths configured") + + # Check API keys and show setup if needed + if not check_all_api_keys(api_key_manager): + logger.info("API keys not verified") + render(api_key_manager) + return + else: + logger.info("All API keys verified") + # Remove the CSS that hides the sidebar + st.markdown(""" + + """, unsafe_allow_html=True) + setup_environment_paths() sidebar_configuration() setup_tabs() - modify_prompts_sidebar() 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", + logger.debug("Setting up environment paths") + try: + os.environ["SEARCH_SAVE_FILE"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_web_research", f"web_research_report_{datetime.now().strftime('%Y-%m-%d_%H-%M-%S')}") - os.environ["IMG_SAVE_DIR"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_content") - os.environ["CONTENT_SAVE_DIR"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_content") - os.environ["PROMPTS_DIR"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_prompts") - os.environ["ALWRITY_CONFIG"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_config", "main_config.json") - - -def modify_prompts_sidebar(): - """Provides a sidebar for modifying prompts.""" - st.sidebar.title("๐ Modify Prompts") - prompts = read_prompts() - - if prompts: - edited_prompts = [] - for i, prompt in enumerate(prompts): - edited_prompt = st.sidebar.text_area(f"Prompt {i+1}", prompt) - edited_prompts.append(edited_prompt) - - if st.sidebar.button("Save Prompts"): - write_prompts(edited_prompts) - st.sidebar.success("Prompts saved successfully!") - else: - st.sidebar.warning("No prompts found in the file.") + os.environ["IMG_SAVE_DIR"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_content") + os.environ["CONTENT_SAVE_DIR"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_content") + os.environ["PROMPTS_DIR"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_prompts") + os.environ["ALWRITY_CONFIG"] = os.path.join(os.getcwd(), "lib", "workspace", "alwrity_config", "main_config.json") + logger.info("Environment paths configured successfully") + except Exception as e: + logger.error(f"Error setting up environment paths: {str(e)}", exc_info=True) + raise # Functions for the main options @@ -278,34 +172,6 @@ def ai_writers(): st.subheader("Exiting, Getting Lost. But.... I have nowhere to go ๐ฅน๐ฅน") -def content_planning_tools(): - st.markdown("""**Alwrity content Ideation & Planning** : Provide few keywords to do comprehensive web research. - Provide few keywords to get Google, Neural, pytrends analysis. Know keywords, blog titles to target. - Generate months long content calendar around given keywords.""") - - options = [ - "Keywords Researcher", - "Competitor Analysis", - "Content Calender Ideator" - ] - choice = st.radio("Select a content planning tool:", options, index=0, format_func=lambda x: f"๐ {x}") - - if choice == "Keywords Researcher": - do_web_research() - elif choice == "Competitor Analysis": - competitor_analysis() - 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(): st.title("๐ง Alwrity Brain, Better than yours!") diff --git a/install.bat b/install.bat new file mode 100644 index 00000000..c2a16b67 --- /dev/null +++ b/install.bat @@ -0,0 +1,39 @@ +@echo off +echo Welcome to ALwrity Installer +echo ============================ +echo. + +:: Check if Python 3.11 is installed +python --version 2>nul | findstr /i "3.11" >nul +if errorlevel 1 ( + echo Python 3.11 is not installed or not in PATH + echo Please install Python 3.11 from https://www.python.org/downloads/release/python-3116/ + echo Make sure to check "Add Python 3.11 to PATH" during installation + echo. + echo Press any key to open the download page... + pause >nul + start https://www.python.org/downloads/release/python-3116/ + exit /b 1 +) + +:: Create virtual environment if it doesn't exist +if not exist "venv" ( + echo Creating virtual environment... + python -m venv venv +) + +:: Activate virtual environment and install requirements +echo Activating virtual environment... +call venv\Scripts\activate.bat + +echo Upgrading pip... +python -m pip install --upgrade pip + +echo Installing ALwrity... +python setup.py install + +echo. +echo Installation complete! +echo To start ALwrity, open a new command prompt and type: alwrity +echo. +pause \ No newline at end of file diff --git a/install_dependencies.py b/install_dependencies.py deleted file mode 100644 index a1b07edd..00000000 --- a/install_dependencies.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python3 -""" -Installation helper script for AI-Writer -This script checks for required system dependencies and guides the user through installation -""" - -import os -import sys -import platform -import subprocess -import shutil -import datetime -import socket -import traceback - -def log_error(error_type, details): - """ - Logs installation errors to a file with timestamp and system information. - - Args: - error_type: Type of error (e.g., 'Python Version Check', 'Rust Installation') - details: Detailed error message - """ - log_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'install_errors.log') - timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") - - # Collect system information - system_info = { - "OS": platform.system(), - "OS Version": platform.version(), - "Architecture": platform.machine(), - "Python Version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}", - "Hostname": socket.gethostname() - } - - # Format the log entry - log_entry = f"[{timestamp}] ERROR: {error_type}\n" - log_entry += f"Details: {details}\n" - log_entry += "System Information:\n" - for key, value in system_info.items(): - log_entry += f" {key}: {value}\n" - log_entry += "-" * 80 + "\n" - - # Write to log file - with open(log_file, 'a') as f: - f.write(log_entry) - - print(f"Error logged to {log_file}") - -def check_python_version(): - print("Checking Python version...") - version = sys.version_info - if version.major < 3 or (version.major == 3 and version.minor < 10): - error_msg = f"Python 3.10+ is required. Found Python {version.major}.{version.minor}" - print(f"Error: {error_msg}") - log_error("Python Version Check", error_msg) - return False - - print(f"โ Python {version.major}.{version.minor}.{version.micro} found") - return True - -def check_visual_cpp_build_tools(): - if platform.system() != "Windows": - return True - - print("Checking for Visual C++ Build Tools...") - - # Check if cl.exe exists in PATH - if shutil.which("cl"): - print("โ Visual C++ Build Tools found") - return True - - error_msg = "Visual C++ Build Tools not found. Required for building certain Python packages." - print("โ Visual C++ Build Tools not found") - print("\nVisual C++ Build Tools are required to build certain Python packages.") - print("To install Visual C++ Build Tools:") - print("Option 1: Run this command in an administrative PowerShell:") - print(" winget install Microsoft.VisualStudio.2022.BuildTools --silent --override \"--wait --quiet --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended\"") - print("\nOption 2: Download and install from the official Microsoft website:") - print(" https://visualstudio.microsoft.com/visual-cpp-build-tools/") - - log_error("Visual C++ Build Tools Check", error_msg) - return False - -def check_rust_compiler(): - print("Checking for Rust compiler...") - - # Check if rustc exists in PATH - if shutil.which("rustc"): - print("โ Rust compiler found") - return True - - error_msg = "Rust compiler not found. Required for building certain Python packages." - print("โ Rust compiler not found") - if platform.system() == "Windows": - print("\nTo install Rust on Windows, run:") - print(" Invoke-WebRequest -Uri https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe -OutFile rustup-init.exe") - print(" ./rustup-init.exe -y") - else: - print("\nTo install Rust on Linux/macOS, run:") - print(" curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y") - print(" source $HOME/.cargo/env") - - log_error("Rust Compiler Check", error_msg) - return False - -def main(): - print("AI-Writer Dependency Checker\n") - - all_checks_passed = True - - # Run dependency checks - if not check_python_version(): - all_checks_passed = False - - if not check_visual_cpp_build_tools(): - all_checks_passed = False - - if not check_rust_compiler(): - all_checks_passed = False - - # If all checks pass, create virtual environment and install requirements - if all_checks_passed: - print("\nAll system dependencies found!") - - # Ask user if they want to proceed with installation - response = input("\nWould you like to create a virtual environment and install Python dependencies? (y/n): ") - if response.lower() == 'y': - print("\nCreating virtual environment...") - try: - if platform.system() == "Windows": - venv_result = os.system("python -m venv venv") - if venv_result != 0: - raise Exception(f"Failed to create virtual environment, exit code: {venv_result}") - install_result = os.system("venv\\Scripts\\activate && pip install -r requirements.txt") - if install_result != 0: - raise Exception(f"Failed to install dependencies, exit code: {install_result}") - else: - venv_result = os.system("python3 -m venv venv") - if venv_result != 0: - raise Exception(f"Failed to create virtual environment, exit code: {venv_result}") - install_result = os.system("source venv/bin/activate && pip install -r requirements.txt") - if install_result != 0: - raise Exception(f"Failed to install dependencies, exit code: {install_result}") - except Exception as e: - error_msg = str(e) - print(f"\nError during installation: {error_msg}") - log_error("Dependency Installation", f"{error_msg}\n{traceback.format_exc()}") - print("Please check the install_errors.log file for details.") - - print("\nInstallation complete! To run the application:") - print("1. Activate the virtual environment:") - if platform.system() == "Windows": - print(" venv\\Scripts\\activate") - else: - print(" source venv/bin/activate") - print("2. Run the application:") - print(" streamlit run alwrity.py") - else: - print("\nSkipping dependency installation. You can install them manually with:") - print("1. Create a virtual environment: python -m venv venv") - print("2. Activate the virtual environment") - print("3. Install dependencies: pip install -r requirements.txt") - else: - print("\nPlease install the missing dependencies and try again.") - print("Check the install_errors.log file for detailed error information.") -if __name__ == "__main__": - main() \ No newline at end of file diff --git a/lib/ai_marketing_tools/ai_backlinking.py b/lib/ai_marketing_tools/ai_backlinking.py index 856daef3..8e25bd34 100644 --- a/lib/ai_marketing_tools/ai_backlinking.py +++ b/lib/ai_marketing_tools/ai_backlinking.py @@ -24,14 +24,14 @@ # 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. +# 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.โ +# 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): @@ -50,7 +50,7 @@ # 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. +# If there's no reply, the system can send polite follow-up reminders at pre-set intervals. # #Key Features: # @@ -71,7 +71,7 @@ # # 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. +# 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. @@ -89,13 +89,13 @@ # 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. +# 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. +# 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. @@ -130,7 +130,7 @@ import sys -from googlesearch import search +# from googlesearch import search # Temporarily disabled for future enhancement from loguru import logger from lib.ai_web_researcher.firecrawl_web_crawler import scrape_website from lib.gpt_providers.text_generation.main_text_generation import llm_text_gen @@ -180,48 +180,32 @@ def find_backlink_opportunities(keyword): 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(f"Contact details found for {url}: {contact_info}") + # Temporarily disabled Google search functionality + # 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(f"Contact details found for {url}: {contact_info}") + + # Placeholder return for now + return [] - # 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 search_for_urls(query): + """ + Search for URLs using Google search. + + Args: + query (str): The search query. + + Returns: + list: List of URLs found. + """ + # Temporarily disabled Google search functionality + # return list(search(query, num_results=10)) + return [] def compose_personalized_email(website_data, insights, user_proposal): """ @@ -300,24 +284,6 @@ def send_email(smtp_server, smtp_port, smtp_user, smtp_password, to_email, subje logger.error(f"Failed to send email to {to_email}: {e}") return False -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(f"Failed to do GoogleSearch: {err}") - def extract_contact_info(website_data): """ Extract contact information from website data. diff --git a/lib/ai_seo_tools/on_page_seo_analyzer.py b/lib/ai_seo_tools/on_page_seo_analyzer.py index 8ba398cd..9847d90f 100644 --- a/lib/ai_seo_tools/on_page_seo_analyzer.py +++ b/lib/ai_seo_tools/on_page_seo_analyzer.py @@ -2,7 +2,7 @@ import os import json import streamlit as st from tenacity import retry, stop_after_attempt, wait_random_exponential -import cloudscraper +import crawl4ai from bs4 import BeautifulSoup import requests import csv @@ -18,7 +18,7 @@ from ..gpt_providers.text_generation.main_text_generation import llm_text_gen def fetch_and_parse_html(url): """ - Fetches HTML content from the given URL using CloudScraper and parses it with BeautifulSoup. + Fetches HTML content from the given URL using crawl4ai and parses it with BeautifulSoup. Args: url (str): The URL of the webpage to fetch. @@ -27,9 +27,8 @@ def fetch_and_parse_html(url): BeautifulSoup: Parsed HTML content. """ try: - scraper = cloudscraper.create_scraper() - html = scraper.get(url) - soup = BeautifulSoup(html.text, 'html.parser') + html = crawl4ai.get(url) + soup = BeautifulSoup(html, 'html.parser') return soup except Exception as e: st.error(f"โ ๏ธ Error fetching or parsing HTML: {e}") diff --git a/lib/ai_seo_tools/textstaty.py b/lib/ai_seo_tools/textstaty.py index f7c55942..c6716187 100644 --- a/lib/ai_seo_tools/textstaty.py +++ b/lib/ai_seo_tools/textstaty.py @@ -1,7 +1,35 @@ -import textstat -import streamlit as st +"""Text analysis tools using textstat.""" -st.set_page_config(layout="wide", page_title="Text Readability Analyzer", page_icon=":book:") +import streamlit as st +from textstat import textstat + +def analyze_text(text): + """Analyze text using textstat metrics.""" + if not text: + st.warning("Please enter some text to analyze.") + return + + # Calculate various metrics + metrics = { + "Flesch Reading Ease": textstat.flesch_reading_ease(text), + "Flesch-Kincaid Grade Level": textstat.flesch_kincaid_grade(text), + "Gunning Fog Index": textstat.gunning_fog(text), + "SMOG Index": textstat.smog_index(text), + "Automated Readability Index": textstat.automated_readability_index(text), + "Coleman-Liau Index": textstat.coleman_liau_index(text), + "Linsear Write Formula": textstat.linsear_write_formula(text), + "Dale-Chall Readability Score": textstat.dale_chall_readability_score(text), + "Readability Consensus": textstat.readability_consensus(text) + } + + # Display metrics in a clean format + st.subheader("Text Analysis Results") + for metric, value in metrics.items(): + st.metric(metric, f"{value:.2f}") + + # Add visualizations + st.subheader("Visualization") + st.bar_chart(metrics) st.title("๐ Text Readability Analyzer: Making Your Content Easy to Read") @@ -10,122 +38,6 @@ st.write(""" Just paste in a sample of your text, and we'll break down the readability scores and offer actionable tips! """) - -def analyze_text(test_data): - """ - Analyzes the readability of the provided text and returns a dictionary with the results. - - Parameters: - test_data (str): The text to be analyzed. - - Returns: - dict: A dictionary containing readability scores and additional metrics. - """ - return { - "Flesch Reading Ease": { - "score": textstat.flesch_reading_ease(test_data), - "description": "This score rates your text on a scale of 0-100, with higher scores being easier to read.", - "tips": [ - "Score below 30? Simplify your text by breaking down complex sentences, using shorter words, and avoiding jargon.", - "Score around 60-70? You're in the 'standard' range.", - "Score over 90? Your text is very easy to read. Add some complexity or sophistication if needed." - ] - }, - "Flesch-Kincaid Grade Level": { - "score": textstat.flesch_kincaid_grade(test_data), - "description": "This formula estimates the US school grade level needed to understand your text.", - "tips": [ - "High Score? Your writing might be too complex for your target audience.", - "Low Score? Your audience might find the text too simple.", - "Match Your Audience: Tailor the complexity to your readers." - ] - }, - "SMOG Index": { - "score": textstat.smog_index(test_data), - "description": "This formula measures text complexity by looking at the number of long words and sentences.", - "tips": [ - "Best for texts with at least 30 sentences.", - "Adjust complexity to match your target audience." - ] - }, - "Coleman-Liau Index": { - "score": textstat.coleman_liau_index(test_data), - "description": "This formula uses sentence length and the number of syllables per word to estimate the reading level." - }, - "Automated Readability Index (ARI)": { - "score": textstat.automated_readability_index(test_data), - "description": "Estimates the grade level required to comprehend your text." - }, - "Dale-Chall Readability Score": { - "score": textstat.dale_chall_readability_score(test_data), - "description": "Focuses on the number of uncommon words (not on a list of 3000 common words) and sentence length.", - "tips": [ - "Easy to Understand: Aim for a score around the reading level of your audience.", - "High School Level? Scores between 9 and 12 indicate a high school reading level.", - "Beyond High School? Scores above 12 are usually for a college-level audience." - ] - }, - "Gunning Fog": { - "score": textstat.gunning_fog(test_data), - "description": "Calculates the grade level required to understand the text." - }, - "Linsear Write Formula": { - "score": textstat.linsear_write_formula(test_data), - "description": "Estimates the US grade level needed to understand the text." - }, - "Text Standard (Consensus)": { - "score": textstat.text_standard(test_data), - "description": "A consensus estimate of the US grade level needed to understand your text, based on multiple readability scores." - }, - "Spache Readability": { - "score": textstat.spache_readability(test_data), - "description": "Best for analyzing text for children, typically up to grade 4.", - "tips": [ - "Considers the number of unfamiliar words and the length of sentences." - ] - }, - "McAlpine EFLAW": { - "score": textstat.mcalpine_eflaw(test_data), - "description": "Evaluates text for foreign language learners, focusing on 'miniwords' and sentence length.", - "tips": [ - "Target Score: Aim for a score of 25 or less." - ] - }, - "Reading Time": { - "score": textstat.reading_time(test_data), - "description": "Estimated reading time in minutes." - }, - "Syllable Count": { - "score": textstat.syllable_count(test_data), - "description": "The number of syllables in the text." - }, - "Word Count": { - "score": textstat.lexicon_count(test_data), - "description": "The number of words in the text." - }, - "Sentence Count": { - "score": textstat.sentence_count(test_data), - "description": "The number of sentences in the text." - }, - "Character Count": { - "score": textstat.char_count(test_data), - "description": "The number of characters in the text." - }, - "Letter Count (without punctuation)": { - "score": textstat.letter_count(test_data), - "description": "The number of letters without punctuation." - }, - "Polysyllable Count": { - "score": textstat.polysyllabcount(test_data), - "description": "The number of polysyllabic words in the text." - }, - "Monosyllable Count": { - "score": textstat.monosyllabcount(test_data), - "description": "The number of monosyllabic words in the text." - } - } - - text_input = st.text_area("Paste your text here:", height=200) if st.button("Analyze!"): @@ -134,18 +46,7 @@ if st.button("Analyze!"): if not test_data.strip(): st.error("Please enter text to analyze.") else: - results = analyze_text(test_data) - - st.subheader("Readability Scores:") - st.write("---") - for metric, data in results.items(): - st.markdown(f"**{metric}:** {data['score']}") - st.markdown(f"* **What It Means:** {data['description']}") - if 'tips' in data: - st.markdown("* **Actionable Tips:**") - for tip in data['tips']: - st.markdown(f" * {tip}") - st.write(" ") + analyze_text(test_data) st.subheader("Key Takeaways:") st.write("---") diff --git a/lib/ai_seo_tools/webpage_content_analysis.py b/lib/ai_seo_tools/webpage_content_analysis.py index 7e4663d7..9cbefe7d 100644 --- a/lib/ai_seo_tools/webpage_content_analysis.py +++ b/lib/ai_seo_tools/webpage_content_analysis.py @@ -1,3 +1,5 @@ +"""Webpage content analysis tool.""" + import streamlit as st import requests from bs4 import BeautifulSoup @@ -7,8 +9,7 @@ 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:") +from urllib.parse import urlparse st.title("๐ง Web Content Analyzer: Uncover Hidden Insights with AI! ๐ง ") st.write(""" @@ -39,19 +40,36 @@ if st.button("Analyze with AI!"): st.stop() try: + # Validate URL + parsed_url = urlparse(url) + if not parsed_url.scheme: + url = "https://" + url + + # Fetch webpage content 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()] - + response.raise_for_status() + + # Parse HTML + soup = BeautifulSoup(response.text, 'html.parser') + + # Extract content + title = soup.title.string if soup.title else "No title found" + meta_description = soup.find('meta', {'name': 'description'}) + description = meta_description['content'] if meta_description else "No description found" + + # Display results + st.subheader("Page Analysis") + st.metric("Title", title) + st.metric("Description", description) + + # Content statistics + text_content = soup.get_text() + words = text_content.split() + st.metric("Word Count", len(words)) + st.metric("Unique Words", len(set(words))) + # Frequency analysis (same as before) - freq = nltk.FreqDist(final_words) + freq = nltk.FreqDist(words) keywords = freq.most_common(10) df_keywords = pd.DataFrame(keywords, columns=("Keyword", "Frequency")) @@ -60,19 +78,19 @@ if st.button("Analyze with AI!"): 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}") + ai_theme = conversation_chain.run(f"What is the main theme or topic of this content? \n {text_content}") 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}") + ai_keywords = conversation_chain.run(f"What other relevant keywords might be helpful to target for this content? \n {text_content}") 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}") + ai_improvement = conversation_chain.run(f"What could be done to improve this content for clarity, engagement, or SEO? \n {text_content}") st.markdown(f" {ai_improvement}") # --- Display Frequency Results --- @@ -94,3 +112,5 @@ if st.button("Analyze with AI!"): """) except requests.exceptions.RequestException as e: st.error(f"Oops! Something went wrong fetching the URL. Error: {e}") + except Exception as e: + st.error(f"An error occurred: {e}") diff --git a/lib/ai_seo_tools/wordcloud.py b/lib/ai_seo_tools/wordcloud.py index 7f5201ea..d04f6b90 100644 --- a/lib/ai_seo_tools/wordcloud.py +++ b/lib/ai_seo_tools/wordcloud.py @@ -1,3 +1,5 @@ +"""Word cloud generation tool.""" + import streamlit as st import requests from bs4 import BeautifulSoup @@ -5,8 +7,8 @@ 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:") +from wordcloud import WordCloud +import matplotlib.pyplot as plt st.title("๐ Web Content Analyzer: Uncover Your Words' Power! ๐") st.write(""" @@ -86,3 +88,26 @@ if st.button("Analyze Your Content!"): except requests.exceptions.RequestException as e: st.error(f"Oops! Something went wrong fetching the URL. Error: {e}") + +def generate_wordcloud(text): + """Generate a word cloud from the given text.""" + if not text: + st.warning("Please enter some text to generate a word cloud.") + return + + # Create and generate a word cloud image + wordcloud = WordCloud(width=800, height=400, background_color='white').generate(text) + + # Display the word cloud + st.subheader("Word Cloud Visualization") + fig, ax = plt.subplots(figsize=(10, 5)) + ax.imshow(wordcloud, interpolation='bilinear') + ax.axis('off') + st.pyplot(fig) + + # Add some statistics + st.subheader("Text Statistics") + words = text.split() + unique_words = set(words) + st.metric("Total Words", len(words)) + st.metric("Unique Words", len(unique_words)) diff --git a/lib/ai_writers/ai_blog_rewriter.py b/lib/ai_writers/ai_blog_rewriter.py index 58307157..683fcf70 100644 --- a/lib/ai_writers/ai_blog_rewriter.py +++ b/lib/ai_writers/ai_blog_rewriter.py @@ -1,3 +1,5 @@ +"""AI-powered blog rewriter tool.""" + import streamlit as st from bs4 import BeautifulSoup import requests @@ -9,12 +11,6 @@ from exa_py import Exa generator = pipeline('text-generation', model='gpt-3') # Example, adjust based on your model def main(): - st.set_page_config( - page_title="AI Blog Content Refresher", - page_icon=":pencil2:", - layout="wide" - ) - st.markdown("Configure your AI service providers for content generation
+Power your content with GPT-4 and GPT-3.5 models
+Leverage Google's powerful Gemini models
+Access Claude for advanced content generation
+Use Mistral's efficient language models
+Configure your research preferences and provide user information
+Configure your AI research providers for content analysis and research
+Step-by-step guide:
+Note: SerpAPI provides real-time search results from multiple engines.
+Step-by-step guide:
+Note: Firecrawl provides powerful web content extraction and analysis capabilities.
+Step-by-step guide:
+Note: Tavily provides AI-powered semantic search capabilities.
+Step-by-step guide:
+Note: Metaphor/Exa provides neural search capabilities for deep research.
+Microsoft's powerful search API with web, news, and image search capabilities.
+ +Google's programmable search engine with customizable search parameters.
+ +These integrations are under development and will be available soon!
+Connect your content platforms and tools
+Connect your website platforms for seamless content publishing
+Connect your WordPress site for direct content publishing.
+Connect your Wix site for direct content publishing.
+Connect your social media accounts for content distribution
+Connect your Facebook account for content sharing.
+Connect your Instagram account for content sharing.
+Connect your analytics tools for content performance tracking
+Connect your Google Search Console for SEO insights.
+Please configure the required keys before proceeding.
+Your configuration has been saved and you're ready to use ALwrity.
+Customize your content generation experience
+Choose how you want your content to be written.
+Define your brand's personality and voice.
+Configure advanced content generation settings.
+Configure your content generation preferences and writing style
+No website URL? No problem! You can provide written samples of your content instead.
+Share your best articles, blog posts, or any content that represents your writing style.
+Enter a website URL or provide content samples to analyze your writing style and get personalized recommendations.
" + ), unsafe_allow_html=True) + + # Create two columns for the layout + col1, col2 = st.columns([2, 1]) + + with col1: + # Website URL input + st.markdown("### Website URL") + url = st.text_input( + "Enter your website URL", + placeholder="https://example.com", + help="Provide your website URL to analyze your content style. Leave empty if you want to provide written samples instead." + ) + logger.debug(f"Website URL input value: {url}") + + # Alternative: Written samples + if not url: + st.markdown("### Written Samples") + st.markdown(get_info_section(""" +No website URL? No problem! You can provide written samples of your content instead.
+Share your best articles, blog posts, or any content that represents your writing style.
+ """), unsafe_allow_html=True) + samples = st.text_area( + "Paste your content samples here", + help="Paste 2-3 samples of your best content. This helps ALwrity understand your writing style." + ) + logger.debug(f"Sample text length: {len(samples) if samples else 0}") + + st.markdown('', unsafe_allow_html=True) + + # ALwrity Style button + st.markdown("", unsafe_allow_html=True) + if st.button("๐จ ALwrity Style", use_container_width=True): + if url: + with st.status("Starting style analysis...", expanded=True) as status: + try: + logger.info(f"Starting style analysis for URL: {url}") + + # Step 1: Initialize crawler + status.update(label="Step 1/4: Initializing web crawler...", state="running") + crawler_service = AsyncWebCrawlerService() + + # Step 2: Crawl website + status.update(label="Step 2/4: Crawling website content...", state="running") + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + result = loop.run_until_complete(crawler_service.crawl_website(url)) + loop.close() + + if result.get('success', False): + content = result.get('content', {}) + + # Step 3: Initialize style analyzer + status.update(label="Step 3/4: Analyzing content style...", state="running") + style_analyzer = StyleAnalyzer() + + # Step 4: Perform style analysis + status.update(label="Step 4/4: Generating style recommendations...", state="running") + style_analysis = style_analyzer.analyze_content_style(content) + + if style_analysis.get('error'): + status.update(label="Analysis failed", state="error") + st.error(f"Style analysis failed: {style_analysis['error']}") + else: + status.update(label="Analysis complete!", state="complete") + # Display style analysis results + display_style_analysis(style_analysis) + + # Display original content in tabs + tab1, tab2, tab3 = st.tabs(["Content", "Metadata", "Links"]) + + with tab1: + st.markdown("### Main Content") + st.markdown(content.get('main_content', 'No content found')) + + with tab2: + st.markdown("### Metadata") + st.markdown(f""" + **Title:** {content.get('title', 'No title found')} + + **Description:** {content.get('description', 'No description found')} + + **Meta Tags:** + {content.get('meta_tags', {})} + """) + + with tab3: + st.markdown("### Links") + for link in content.get('links', []): + st.markdown(f"- [{link.get('text', '')}]({link.get('href', '')})") + + else: + status.update(label="Crawling failed", state="error") + st.error(f"Failed to analyze website: {result.get('error', 'Unknown error')}") + + except Exception as e: + logger.error(f"Error during style analysis: {str(e)}") + st.error(f"Analysis failed: {str(e)}") + elif samples: + with st.spinner("Analyzing content samples..."): + try: + # TODO: Implement sample text analysis + st.info("Sample text analysis coming soon!") + except Exception as e: + logger.error(f"Error analyzing samples: {str(e)}") + st.error(f"Analysis failed: {str(e)}") + else: + st.warning("Please provide either a website URL or content samples") + + with col2: + st.markdown(""" + ### How ALwrity Discovers Your Style + + **AI-Powered Style Analysis** + + ALwrity AI analyzes your existing content to understand your unique writing style and preferences. This helps us generate content that matches your voice perfectly. + + **Step 1: Content Analysis** + + We'll analyze your website content or written samples to understand: + + - Writing tone and voice + - Vocabulary and language style + - Content structure and formatting + - Target audience and engagement style + + **Step 2: Style Recommendations** + + Based on the analysis, we'll provide: + + - Personalized writing guidelines + - Content structure templates + - Tone and voice recommendations + - Audience engagement strategies + + **Step 3: Content Generation** + + Finally, we'll use these insights to: + + - Generate content that matches your style + - Maintain consistency across all content + - Optimize for your target audience + - Ensure brand voice alignment + """) + + except Exception as e: + logger.error(f"Error in render_test_config_settings: {str(e)}") + st.error(f"An error occurred: {str(e)}") + +if __name__ == "__main__": + logger.info("Starting test config settings page") + render_test_config_settings() + logger.info("Test config settings page rendered successfully") \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index 11b8c695..4760f08b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,47 +1,48 @@ -requests -typer[all] -rich -python-dotenv -loguru -openai -crewai[tools] -crewai_tools -python-docx -PyPDF2 -google.generativeai -anthropic -tenacity -tavily-python -tabulate -metaphor_python -exa_py -GoogleNews -langchain-google-genai -clint -scikit-learn -matplotlib -plotly -textstat -requests_html -pytrends -pytube -pytubefix -readability -wordcloud -prompt_toolkit -ipython -html2image -lxml_html_clean -streamlit -yfinance -pandas_ta -firecrawl-py -gTTS -validators -streamlit-mic-recorder -tinify -cloudscraper -xmlschema -moviepy -googlesearch-python -streamlit-aggrid +requests>=2.31.0 +typer>=0.9.0 +rich>=13.7.0 +python-dotenv>=1.0.0 +beautifulsoup4==4.12.2 +aiohttp>=3.11.11 +openai>=1.3.7 +PyPDF2>=3.0.1 +google-generativeai<0.9.0,>=0.8.0 +anthropic>=0.18.1 +tenacity>=8.2.3 +tabulate>=0.9.0 +metaphor-python==0.1.16 +exa_py>=1.9.1 +GoogleNews>=1.6.15 +langchain-google-genai>=2.0.10 +clint>=0.5.1 +numpy>=1.22.4,<2.0.0 +pandas>=2.0.3 +scikit-learn>=1.3.2 +matplotlib>=3.8.2 +plotly>=5.18.0 +textstat>=0.7.3 +requests_html>=0.10.0 +pytrends>=4.9.0 +pytube>=15.0.0 +pytubefix>=8.12.2 +readability>=0.3.2 +wordcloud>=1.9.3 +prompt_toolkit>=3.0.43 +html2image>=2.0.5 +lxml[html_clean]>=5.3.0 +lxml_html_clean>=0.4.1 +streamlit>=1.29.0 +yfinance>=0.2.36 +pandas_ta>=0.3.14b0 +firecrawl-py>=1.14.1 +gTTS>=2.5.1 +streamlit-mic-recorder>=0.0.8 +streamlit-aggrid>=1.1.2 +crawl4ai>=0.5.0 +playwright>=1.51.0 +loguru==0.7.2 +tavily-python>=0.2.8 +tinify>=1.6.0 +validators>=0.20.0 +python-whois==0.9.5 +dnspython \ No newline at end of file diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..7ab576a6 --- /dev/null +++ b/setup.py @@ -0,0 +1,157 @@ +import sys +import os +import platform +import subprocess +import shutil +import datetime +import socket +import traceback +import pkg_resources +from setuptools import setup, find_packages + +def log_error(error_type, details): + """ + Logs installation errors to a file with timestamp and system information. + """ + log_file = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'install_errors.log') + timestamp = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + + system_info = { + "OS": platform.system(), + "OS Version": platform.version(), + "Architecture": platform.machine(), + "Python Version": f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}", + "Hostname": socket.gethostname() + } + + log_entry = f"[{timestamp}] ERROR: {error_type}\n" + log_entry += f"Details: {details}\n" + log_entry += "System Information:\n" + for key, value in system_info.items(): + log_entry += f" {key}: {value}\n" + log_entry += "-" * 80 + "\n" + + with open(log_file, 'a') as f: + f.write(log_entry) + + print(f"Error logged to {log_file}") + +def check_system_dependencies(): + """Check for required system dependencies.""" + print("Checking system dependencies...") + all_checks_passed = True + + # Check Python version + print("Checking Python version...") + if sys.version_info < (3, 11) or sys.version_info >= (3, 12): + error_msg = "ALwrity requires Python 3.11.x" + print(f"Error: {error_msg}") + log_error("Python Version Check", error_msg) + all_checks_passed = False + else: + print(f"โ Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} found") + + # Check Visual C++ Build Tools on Windows + if platform.system() == "Windows": + print("Checking for Visual C++ Build Tools...") + if not shutil.which("cl"): + error_msg = "Visual C++ Build Tools not found" + print("โ Visual C++ Build Tools not found") + print("\nTo install Visual C++ Build Tools, run in an administrative PowerShell:") + print("winget install Microsoft.VisualStudio.2022.BuildTools --silent --override \"--wait --quiet --add Microsoft.VisualStudio.Workload.VCTools --includeRecommended\"") + log_error("Visual C++ Build Tools Check", error_msg) + all_checks_passed = False + else: + print("โ Visual C++ Build Tools found") + + # Check Rust compiler + print("Checking for Rust compiler...") + if not shutil.which("rustc"): + error_msg = "Rust compiler not found" + print("โ Rust compiler not found") + if platform.system() == "Windows": + print("\nTo install Rust on Windows, run:") + print("Invoke-WebRequest -Uri https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe -OutFile rustup-init.exe") + print("./rustup-init.exe -y") + else: + print("\nTo install Rust on Linux/macOS, run:") + print("curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y") + print("source $HOME/.cargo/env") + log_error("Rust Compiler Check", error_msg) + all_checks_passed = False + else: + print("โ Rust compiler found") + + return all_checks_passed + +def get_requirements(): + """Read requirements from requirements.txt.""" + with open('requirements.txt') as f: + requirements = [line.strip() for line in f if line.strip() and not line.startswith('#')] + return requirements + +def install_requirements(requirements): + """Install each requirement, showing progress.""" + print("Installing required packages...") + for requirement in requirements: + try: + print(f"Installing {requirement}...") + subprocess.check_call([sys.executable, "-m", "pip", "install", requirement]) + except subprocess.CalledProcessError as e: + error_msg = f"Error installing {requirement}: {e}" + print(error_msg) + log_error("Package Installation", error_msg) + sys.exit(1) + +def main(): + """Main installation function.""" + print("ALwrity Installation\n") + + # Check system dependencies + if not check_system_dependencies(): + print("\nPlease install the missing dependencies and try again.") + print("Check the install_errors.log file for detailed error information.") + sys.exit(1) + + # Create virtual environment if it doesn't exist + if not os.path.exists("venv"): + print("\nCreating virtual environment...") + try: + subprocess.check_call([sys.executable, "-m", "venv", "venv"]) + except subprocess.CalledProcessError as e: + error_msg = f"Failed to create virtual environment: {e}" + print(error_msg) + log_error("Virtual Environment Creation", error_msg) + sys.exit(1) + + # Install requirements + requirements = get_requirements() + install_requirements(requirements) + + # Run setup + setup( + name="alwrity", + version="1.0.0", + description="AI-powered content writing assistant", + author="Your Name", + packages=find_packages(), + python_requires=">=3.11, <3.12", + install_requires=requirements, + entry_points={ + 'console_scripts': [ + 'alwrity=alwrity:main', + ], + }, + ) + + print("\nInstallation complete! To start ALwrity:") + print("1. Activate the virtual environment:") + if platform.system() == "Windows": + print(" .\\venv\\Scripts\\activate") + else: + print(" source venv/bin/activate") + print("2. Run the application:") + print(" streamlit run alwrity.py") + +if __name__ == '__main__': + main() \ No newline at end of file