diff --git a/.gitignore b/.gitignore
index c20efe30..b6b32d43 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,6 +21,10 @@ __pycache__
*.pywpz
*.pywpzp
+lib/workspace/alwrity_web_research/*
+lib/workspace/alwrity_web_research_cache/*
+web_research_report*
+
.swp
.swo
.swn
diff --git a/alwrity.py b/alwrity.py
index b6ffb3fd..e55f793b 100644
--- a/alwrity.py
+++ b/alwrity.py
@@ -1,11 +1,16 @@
import streamlit as st
+import os
+import json
+import base64
+import logging
+from datetime import datetime
# 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
+ initial_sidebar_state="expanded", # Changed from collapsed to expanded
menu_items={
'Get Help': None,
'Report a bug': None,
@@ -13,27 +18,32 @@ st.set_page_config(
}
)
-# Add CSS to hide sidebar during setup
-st.markdown("""
+# Load and apply custom CSS
+with open('lib/workspace/alwrity_ui_styling.css', 'r') as f:
+ css = f.read()
+
+st.markdown(f"""
""", unsafe_allow_html=True)
-import os
-import json
-import base64
-import logging
-from datetime import datetime
-
# Configure logging
logging.basicConfig(
level=logging.DEBUG,
@@ -45,18 +55,13 @@ logging.basicConfig(
)
logger = logging.getLogger(__name__)
-from lib.utils.config_manager import save_config
from lib.utils.ui_setup import setup_ui
-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
-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
+from lib.utils.content_generators import 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.ui_setup import setup_ui, setup_alwrity_ui
+
def process_folder_for_rag(folder_path):
"""Placeholder for the process_folder_for_rag function."""
@@ -94,36 +99,110 @@ def main():
# Check API keys and show setup if needed
if not check_all_api_keys(api_key_manager):
logger.info("API keys not verified")
+ # Add CSS to hide sidebar during setup
+ st.markdown("""
+
+ """, unsafe_allow_html=True)
render(api_key_manager)
return
else:
logger.info("All API keys verified")
- # Remove the CSS that hides the sidebar
+ # Remove the CSS that hides the sidebar and ensure it's expanded
st.markdown("""
+
+ """, unsafe_allow_html=True)
+
+ # Set session state to ensure sidebar stays expanded
+ if 'sidebar_expanded' not in st.session_state:
+ st.session_state.sidebar_expanded = True
+
+ # Force sidebar state
+ st.sidebar.markdown("""
+
""", unsafe_allow_html=True)
-
- setup_environment_paths()
- sidebar_configuration()
- setup_tabs()
+
+ setup_alwrity_ui()
def setup_environment_paths():
diff --git a/lib/utils/alwrity_sidebar.py b/lib/utils/alwrity_sidebar.py
deleted file mode 100644
index 8665bead..00000000
--- a/lib/utils/alwrity_sidebar.py
+++ /dev/null
@@ -1,244 +0,0 @@
-import streamlit as st
-import logging
-
-from .config_manager import save_config
-
-# 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__)
-
-# Sidebar configuration
-def sidebar_configuration():
- """Configure the sidebar with all necessary options."""
- try:
- # Configure sidebar styling
- st.sidebar.markdown("""
-
- """, unsafe_allow_html=True)
-
- logger.info("Initializing sidebar configuration")
- st.sidebar.title("🛠️ Personalization & Settings 🏗️")
-
- with st.sidebar.expander("**👷 Content Personalization**"):
- logger.debug("Setting up content personalization options")
- 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.")
- logger.debug(f"Selected blog tone: {blog_tone}")
-
- 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
- logger.debug(f"Custom tone set to: {custom_tone}")
- else:
- logger.warning("Custom tone not specified")
- 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)
- except Exception as e:
- logger.error(f"Error configuring sidebar: {str(e)}")
- st.error(f"Error configuring sidebar: {str(e)}")
\ No newline at end of file
diff --git a/pages/ai_research_setup_page.py b/pages/ai_research_setup_page.py
deleted file mode 100644
index 5d094cd4..00000000
--- a/pages/ai_research_setup_page.py
+++ /dev/null
@@ -1,50 +0,0 @@
-"""Page for AI Research Setup redirection."""
-
-import streamlit as st
-from loguru import logger
-import sys
-import os
-
-# Configure logger
-logger.remove() # Remove default handler
-logger.add(
- "logs/ai_research_setup_page.log",
- rotation="500 MB",
- retention="10 days",
- level="DEBUG",
- format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}",
- backtrace=True,
- diagnose=True
-)
-logger.add(
- sys.stdout,
- level="INFO",
- format="
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 4760f08b..881f53b4 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ beautifulsoup4==4.12.2 aiohttp>=3.11.11 openai>=1.3.7 PyPDF2>=3.0.1 -google-generativeai<0.9.0,>=0.8.0 +google-genai==1.9.0 anthropic>=0.18.1 tenacity>=8.2.3 tabulate>=0.9.0