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/ai_web_researcher/.gpt_online_researcher.py.swp b/lib/ai_web_researcher/.gpt_online_researcher.py.swp deleted file mode 100644 index 1dd76695..00000000 Binary files a/lib/ai_web_researcher/.gpt_online_researcher.py.swp and /dev/null differ diff --git a/lib/ai_web_researcher/gemini_grounding_search_streamlit.py b/lib/ai_web_researcher/gemini_grounding_search_streamlit.py new file mode 100644 index 00000000..b3535c84 --- /dev/null +++ b/lib/ai_web_researcher/gemini_grounding_search_streamlit.py @@ -0,0 +1,155 @@ +import os +import streamlit as st +from google import genai +from google.genai.types import Tool, GenerateContentConfig, GoogleSearch + +# Set page config +st.set_page_config( + page_title="Gemini Grounding Search", + page_icon="πŸ”", + layout="wide" +) + +# Custom CSS for styling +st.markdown(""" + +""", unsafe_allow_html=True) + +# Title +st.title("Gemini Grounding Search") + +# Initialize Gemini client +if 'GEMINI_API_KEY' not in os.environ: + api_key = st.text_input("Enter your Gemini API Key:", type="password") + if api_key: + os.environ['GEMINI_API_KEY'] = api_key + +# Search input +search_query = st.text_input("Enter your search query:", "When is the next total solar eclipse in the United States?") + +if st.button("Search"): + if 'GEMINI_API_KEY' not in os.environ: + st.error("Please enter your Gemini API Key first!") + else: + try: + client = genai.Client(api_key=os.environ['GEMINI_API_KEY']) + model_id = "gemini-2.0-flash" + + google_search_tool = Tool( + google_search = GoogleSearch() + ) + + with st.spinner("Searching..."): + response = client.models.generate_content( + model=model_id, + contents=search_query, + config=GenerateContentConfig( + tools=[google_search_tool], + response_modalities=["TEXT"], + ) + ) + + # Display search results header + st.header("Search Results") + + # Display the response text + if response.candidates[0].content.parts: + st.markdown('
' + + response.candidates[0].content.parts[0].text.replace('\n', '
') + + '
', + unsafe_allow_html=True) + + # Display the grounding metadata + if hasattr(response.candidates[0], 'grounding_metadata') and \ + hasattr(response.candidates[0].grounding_metadata, 'search_entry_point') and \ + hasattr(response.candidates[0].grounding_metadata.search_entry_point, 'rendered_content'): + + st.header("Related Searches") + rendered_content = response.candidates[0].grounding_metadata.search_entry_point.rendered_content + st.markdown(rendered_content, unsafe_allow_html=True) + + except Exception as e: + st.error(f"An error occurred: {str(e)}") \ No newline at end of file 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/lib/utils/api_key_manager/components/personalization_setup.py b/lib/utils/api_key_manager/components/personalization_setup.py index f4f773c4..cd61fb15 100644 --- a/lib/utils/api_key_manager/components/personalization_setup.py +++ b/lib/utils/api_key_manager/components/personalization_setup.py @@ -8,11 +8,13 @@ from typing import Dict, Any from ..manager import APIKeyManager from ....web_crawlers.async_web_crawler import AsyncWebCrawlerService from ....personalization.style_analyzer import StyleAnalyzer -from pages.style_utils import ( - get_analysis_section, +from lib.utils.style_utils import ( + get_test_config_styles, get_glass_container, get_info_section, - get_example_box + get_example_box, + get_analysis_section, + get_style_guide_html ) from .base import render_navigation_buttons from .alwrity_integrations import render_alwrity_integrations @@ -618,7 +620,7 @@ def render_personalization_setup(api_key_manager: APIKeyManager) -> Dict[str, An st.warning("Please provide either a website URL or content samples") with col2: - st.markdown(""" + st.markdown(get_glass_container(""" ### How ALwrity Discovers Your Style **AI-Powered Style Analysis** @@ -651,10 +653,15 @@ def render_personalization_setup(api_key_manager: APIKeyManager) -> Dict[str, An - Maintain consistency across all content - Optimize for your target audience - Ensure brand voice alignment - """) + """)) # API Configuration Form - st.markdown("### API Configuration") + st.markdown(get_glass_container(""" + ### API Configuration + + Configure your API settings for optimal content generation. + """)) + with st.form("ai_config_form"): # API Keys st.text_input("OpenAI API Key", type="password", key="openai_key") diff --git a/lib/utils/settings_page.py b/lib/utils/settings_page.py new file mode 100644 index 00000000..74f2b9a8 --- /dev/null +++ b/lib/utils/settings_page.py @@ -0,0 +1,438 @@ +import streamlit as st +from loguru import logger +import asyncio +from lib.web_crawlers.async_web_crawler import AsyncWebCrawlerService +from lib.personalization.style_analyzer import StyleAnalyzer +import sys + +# Configure logger +logger.remove() # Remove default handler +logger.add( + "logs/settings_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="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}" +) + +def display_style_analysis(analysis_results: dict): + """Display the style analysis results in a structured format.""" + try: + # Writing Style Section + st.markdown("### 🎨 Writing Style Analysis") + writing_style = analysis_results.get("writing_style", {}) + writing_style_content = f""" + + """ + st.markdown(writing_style_content, unsafe_allow_html=True) + + # Content Characteristics Section + content_chars = analysis_results.get("content_characteristics", {}) + content_chars_content = f""" + + """ + st.markdown(content_chars_content, unsafe_allow_html=True) + + # Target Audience Section + target_audience = analysis_results.get("target_audience", {}) + target_audience_content = f""" + + """ + st.markdown(target_audience_content, unsafe_allow_html=True) + + # Content Type Section + content_type = analysis_results.get("content_type", {}) + content_type_content = f""" + + """ + st.markdown(content_type_content, unsafe_allow_html=True) + + # Recommended Settings Section + recommended = analysis_results.get("recommended_settings", {}) + recommended_content = f""" + + """ + st.markdown(recommended_content, unsafe_allow_html=True) + + except Exception as e: + logger.error(f"Error displaying style analysis: {str(e)}") + st.error(f"Error displaying analysis results: {str(e)}") + +def render_settings_page(): + """Renders the settings page with all configuration options in tabs""" + st.title("πŸ› οΈ Settings & Configuration") + + # Create tabs for different settings categories + tabs = st.tabs([ + "πŸ‘· Content", + "🩻 Images", + "πŸ€– LLM", + "πŸ•΅οΈ Search", + "🎨 AI Personalization" + ]) + + # Content Settings Tab + with tabs[0]: + st.header("Content Personalization") + blog_length = st.text_input( + "**Content Length (words)**", + value="2000", + key="settings_blog_length", + 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, + key="settings_blog_tone", + help="Select the desired tone for the blog content." + ) + + if blog_tone == "Customize": + custom_tone = st.text_input( + "Enter the tone of your content", + key="settings_custom_tone", + 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, + key="settings_blog_demographic", + help="Select the primary audience for the blog content." + ) + + blog_type = st.selectbox( + "**Content Type**", + options=["Informational", "Commercial", "Company", "News", "Finance", "Competitor", "Programming", "Scholar"], + key="settings_blog_type", + 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"], + key="settings_blog_language", + help="Select the language in which the blog will be written." + ) + + blog_output_format = st.selectbox( + "**Content Output Format**", + options=["markdown", "HTML", "plaintext"], + key="settings_blog_output_format", + help="Select the format for the blog output." + ) + + # Images Settings Tab + with tabs[1]: + st.header("Images Personalization") + image_generation_model = st.selectbox( + "**Image Generation Model**", + options=["stable-diffusion", "dalle2", "dalle3"], + key="settings_image_model", + help="Select the model to generate images for the blog." + ) + + number_of_blog_images = st.number_input( + "**Number of Blog Images**", + value=1, + min_value=1, + max_value=10, + key="settings_number_of_images", + help="Specify the number of images to include in the blog." + ) + + # LLM Settings Tab + with tabs[2]: + st.header("LLM Personalization") + gpt_provider = st.selectbox( + "**GPT Provider**", + options=["google", "openai", "minstral"], + key="settings_gpt_provider", + help="Select the provider for the GPT model." + ) + + model = st.text_input( + "**Model**", + value="gemini-1.5-flash-latest", + key="settings_model", + help="Specify the model version to use from the selected provider." + ) + + col1, col2 = st.columns(2) + with col1: + temperature = st.slider( + "Temperature", + min_value=0.1, + max_value=1.0, + value=0.7, + step=0.1, + key="settings_temperature", + help="Controls the creativity level of the generated text." + ) + + max_tokens = st.selectbox( + "Max Tokens", + options=[500, 1000, 2000, 4000, 16000, 32000, 64000], + index=3, + key="settings_max_tokens", + help="Maximum length of the output sequence." + ) + + with col2: + top_p = st.slider( + "Top-p", + min_value=0.0, + max_value=1.0, + value=0.9, + step=0.1, + key="settings_top_p", + help="Controls diversity in text generation." + ) + + frequency_penalty = st.slider( + "Frequency Penalty", + min_value=0.0, + max_value=2.0, + value=1.0, + step=0.1, + key="settings_frequency_penalty", + help="Reduces word repetition in output." + ) + + # Search Settings Tab + with tabs[3]: + st.header("Search Engine Personalization") + geographic_location = st.selectbox( + "**Geographic Location**", + options=["us", "in", "fr", "cn"], + key="settings_geographic_location", + help="Select the geographic location for tailoring search results." + ) + + search_language = st.selectbox( + "**Search Language**", + options=["en", "zn-cn", "de", "hi"], + key="settings_search_language", + help="Select the language for the search results." + ) + + number_of_results = st.number_input( + "**Number of Results**", + value=10, + min_value=1, + max_value=20, + key="settings_number_of_results", + 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"], + key="settings_time_range", + help="Select the time range for filtering search results." + ) + + include_domains = st.text_input( + "**Include Domains**", + value="", + key="settings_include_domains", + help="List specific domains to include in search results (comma-separated)." + ) + + similar_url = st.text_input( + "**Similar URL**", + value="", + key="settings_similar_url", + help="Provide a URL to find similar results." + ) + + # AI Personalization Tab + with tabs[4]: + st.header("🎨 AI Style Analysis") + st.markdown(""" +
+

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", + key="settings_website_url", + help="Provide your website URL to analyze your content style. Leave empty if you want to provide written samples instead." + ) + + # Alternative: Written samples + if not url: + st.markdown("### Written Samples") + st.markdown(""" +
+

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", + key="settings_content_samples", + help="Paste 2-3 samples of your best content. This helps ALwrity understand your writing style." + ) + + # ALwrity Style button + st.markdown("
", unsafe_allow_html=True) + if st.button("🎨 Analyze Style", use_container_width=True, key="settings_analyze_style"): + if url: + with st.status("Starting style analysis...", expanded=True) as status: + try: + # 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("Failed to crawl the website. Please check the URL and try again.") + except Exception as e: + status.update(label="Analysis failed", state="error") + st.error(f"An error occurred during analysis: {str(e)}") + elif samples: + with st.status("Starting style analysis...", expanded=True) as status: + try: + # Initialize style analyzer + status.update(label="Analyzing content style...", state="running") + style_analyzer = StyleAnalyzer() + + # Perform style analysis + style_analysis = style_analyzer.analyze_content_style({"main_content": samples}) + + 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) + except Exception as e: + status.update(label="Analysis failed", state="error") + st.error(f"An error occurred during analysis: {str(e)}") + else: + st.warning("Please provide either a website URL or content samples to analyze.") + + # Save Settings Button + if st.button("πŸ’Ύ Save Settings", type="primary", use_container_width=True, key="settings_save_button"): + # Save all settings to session state + st.session_state.update({ + '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, + 'image_generation_model': image_generation_model, + 'number_of_blog_images': number_of_blog_images, + 'gpt_provider': gpt_provider, + 'model': model, + 'temperature': temperature, + 'top_p': top_p, + 'max_tokens': max_tokens, + 'frequency_penalty': frequency_penalty, + '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 + }) + st.success("βœ… Settings saved successfully!") \ No newline at end of file diff --git a/pages/style_utils.py b/lib/utils/style_utils.py similarity index 64% rename from pages/style_utils.py rename to lib/utils/style_utils.py index cf0345cc..049f5038 100644 --- a/pages/style_utils.py +++ b/lib/utils/style_utils.py @@ -267,79 +267,147 @@ def get_glassmorphic_styles() -> str: """ +def get_test_config_styles(): + """Returns CSS styles for the test configuration page.""" + return """ + + """ + def get_glass_container(content: str) -> str: - """Wrap content in a glass container.""" + """Returns HTML for a glass-morphism container.""" return f""" -
+
{content}
""" def get_info_section(content: str) -> str: - """Wrap content in an info section.""" + """Returns HTML for an info section.""" return f""" -
+
{content}
""" def get_example_box(content: str) -> str: - """Wrap content in an example box.""" + """Returns HTML for an example box.""" return f""" -
+
{content}
""" def get_analysis_section(title: str, content: str) -> str: - """Create an analysis section with title and content.""" + """Returns HTML for an analysis section.""" return f""" -
+

{title}

{content}
""" def get_style_guide_html() -> str: - """ - Get the style guide HTML content. - - Returns: - str: HTML content for the style guide section - """ + """Returns HTML for the style guide section.""" return """ - ### 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 +
+

Style Guide

+

This section will contain your style guide and brand guidelines.

+
""" def get_test_config_styles() -> str: diff --git a/pages/test_config_settings.py b/lib/utils/test_config_settings.py similarity index 99% rename from pages/test_config_settings.py rename to lib/utils/test_config_settings.py index 1ab9a2c8..316c0de9 100644 --- a/pages/test_config_settings.py +++ b/lib/utils/test_config_settings.py @@ -148,8 +148,8 @@ def render_test_config_settings(): # Set session state for navigation st.session_state.current_step = 4 st.session_state.next_step = "personalization_setup" - # Navigate back to personalization setup - st.switch_page("pages/personalization_setup.py") + # Navigate back to the main page where personalization setup is rendered + st.switch_page("alwrity.py") # Title and description st.title("🎨 Find Your Style with ALwrity") diff --git a/lib/utils/ui_setup.py b/lib/utils/ui_setup.py index fb54c9fd..e2b6d623 100644 --- a/lib/utils/ui_setup.py +++ b/lib/utils/ui_setup.py @@ -4,6 +4,7 @@ from lib.utils.file_processor import load_image from lib.utils.content_generators import content_planning_tools, ai_writers from lib.utils.alwrity_utils import ai_social_writer from lib.utils.seo_tools import ai_seo_tools +from lib.utils.settings_page import render_settings_page def setup_ui(): @@ -67,40 +68,73 @@ def setup_ui(): border-radius: 8px; color: white; } + + /* Sidebar navigation styling */ + .sidebar-nav { + padding: 1rem 0; + } + + .nav-button { + width: 100%; + text-align: left; + padding: 0.5rem 1rem; + background: transparent; + border: none; + color: #2c3e50; + font-weight: 500; + cursor: pointer; + transition: all 0.3s ease; + margin: 0.2rem 0; + border-radius: 4px; + } + + .nav-button:hover { + background: rgba(0,0,0,0.05); + padding-left: 1.5rem; + } + + .nav-button.active { + background: #1565C0; + color: white; + } """, unsafe_allow_html=True) - image_base64 = load_image("lib/workspace/alwrity_logo.png") - st.markdown(f""" -
- Alwrity Logo - Welcome to Alwrity! -
- """, unsafe_allow_html=True) +def setup_alwrity_ui(): + """Sets up the main navigation in the sidebar.""" + # Initialize session state for active tab if not exists + if 'active_tab' not in st.session_state: + st.session_state.active_tab = "Content Planning" -def setup_tabs(): - """Sets up the main tabs in the Streamlit app.""" - tab1, tab2, tab3, tab4, tab5, tab6 = st.tabs( - ["πŸ“…Content Planning", " πŸ“πŸ€–AI Writers", "πŸ€πŸ€–Agents Teams", "πŸ› οΈπŸ”AI SEO tools", "πŸ“±AI Social Tools", " πŸ’¬Ask Alwrity"]) - with tab1: - content_planning_tools() + # Define the navigation items with their icons and functions + nav_items = { + "Content Planning": ("πŸ“…", content_planning_tools), + "AI Writers": ("πŸ“", ai_writers), + "Agents Teams": ("🀝", lambda: st.subheader("Agents Teams - Coming Soon!")), + "AI SEO Tools": ("πŸ”", ai_seo_tools), + "AI Social Tools": ("πŸ“±", ai_social_writer), + "Ask Alwrity": ("πŸ’¬", lambda: ( + st.subheader("Chat with your Data, Chat with any Data.. COMING SOON !"), + st.markdown("Create a collection by uploading files (PDF, MD, CSV, etc), or crawl a data source (Websites, more sources coming soon."), + st.markdown("One can ask/chat, summarize and do semantic search over the uploaded data") + )), + "ALwrity Settings": ("βš™οΈ", render_settings_page) + } - with tab2: - ai_writers() + # Create sidebar navigation + st.sidebar.markdown("### ALwrity Options") + st.sidebar.markdown('', unsafe_allow_html=True) - with tab6: - st.subheader("Chat with your Data, Chat with any Data.. COMING SOON !") - st.markdown("Create a collection by uploading files (PDF, MD, CSV, etc), or crawl a data source (Websites, more sources coming soon.") - st.markdown("One can ask/chat, summarize and do semantic search over the uploaded data") - # alwrity_chat_docqa() + # Display content based on active tab + st.title(f"{nav_items[st.session_state.active_tab][0]} {st.session_state.active_tab}") + nav_items[st.session_state.active_tab][1]() \ No newline at end of file diff --git a/lib/workspace/AskAlwrity-min.ico b/lib/workspace/AskAlwrity-min.ico new file mode 100644 index 00000000..abaf82ce Binary files /dev/null and b/lib/workspace/AskAlwrity-min.ico differ diff --git a/lib/workspace/alwrity_ui_styling.css b/lib/workspace/alwrity_ui_styling.css index f9bc9f76..3a122176 100644 --- a/lib/workspace/alwrity_ui_styling.css +++ b/lib/workspace/alwrity_ui_styling.css @@ -13,13 +13,13 @@ body { /* Main header styling */ .main-header { - font-size: 2.5em; + font-size: 2em; font-weight: bold; color: #1565C0; - margin-bottom: 20px; + margin-bottom: 2px; text-align: center; text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.2); - padding-top: 10px; + padding-top: 1px; } /* Sub-header styling */ @@ -32,49 +32,355 @@ body { text-align: center; } -/* Navigation tabs styling */ -.stTabs [role="tab"] { - font-size: 18px; - font-weight: bold; - color: white; - background: #1565C0; - padding: 6px 10px; - margin: 5px; +/* Enhanced Tab styling with dark red gradients */ +.stTabs { + margin-top: 0.5rem; + background: white; + padding: 0.5rem; + border-radius: 2px; + box-shadow: 0 2px 2px rgba(0, 0, 0, 0.05); +} + +.stTabs [data-baseweb="tab-list"] { + gap: 8px; + background: linear-gradient(135deg, #f8fafc, #f1f5f9); + padding: 8px; border-radius: 8px; - border: 2px solid #ddd; - transition: background 0.3s ease, padding 0.3s ease; } -.stTabs [role="tab"]:hover { - background: #1976D2; +.stTabs [data-baseweb="tab"] { + height: auto; + padding: 12px 20px; + color: #E2E8F0; + border-radius: 8px; + font-weight: 600; + font-size: 15px; + background: linear-gradient(135deg, #4A5568, #2D3748); + border: 1px solid rgba(255, 255, 255, 0.1); + transition: all 0.3s ease; + letter-spacing: 0.3px; + background: white; + border-radius: 6px; + padding: 8px 16px; + font-weight: 600; + color: #475569; + transition: all 0.2s ease; } -.stTabs [role="tab"][aria-selected="true"] { - background: #E3F2FD; - color: #333; - border: 2px solid #1565C0; - font-weight: bold; +.stTabs [data-baseweb="tab"]:hover { + color: #FFFFFF; + background: linear-gradient(135deg, #822727, #991B1B); + border-color: rgba(255, 255, 255, 0.2); + transform: translateY(-1px); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.2); + background: #f1f5f9; + color: #1e293b; } -/* Sidebar header styling */ -.sidebar-header { - font-size: 1.5em; - font-weight: bold; - color: #333; - margin-bottom: 20px; +.stTabs [data-baseweb="tab"][aria-selected="true"] { + color: #FFFFFF; + background: linear-gradient(135deg, #3182CE, #2C5282); + border-color: #DC2626; + box-shadow: 0 4px 12px rgba(220, 38, 38, 0.3); + position: relative; + background: linear-gradient(135deg, #3182ce, #2c5282); + color: white; } -/* Sidebar option styling */ -.sidebar-option { - margin-bottom: 10px; - font-size: 1.5em; - color: #1565C0; +.stTabs [data-baseweb="tab"][aria-selected="true"]::after { + content: ''; + position: absolute; + bottom: -2px; + left: 10%; + width: 80%; + height: 2px; + background: linear-gradient(90deg, transparent, #FFFFFF, transparent); + border-radius: 2px; +} + +.stTabs [data-baseweb="tab-panel"] { + padding: 20px; + background: linear-gradient(135deg, #FFFFFF, #F8FAFC); + border-radius: 12px; + margin-top: 10px; + border: 1px solid rgba(226, 232, 240, 0.8); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); +} + +/* Enhanced tab content for better readability */ +.stTabs [data-baseweb="tab-panel"] p { + color: #1A202C; + line-height: 1.7; + font-size: 15px; +} + +.stTabs [data-baseweb="tab-panel"] ul { + margin-top: 1rem; + margin-bottom: 1rem; + padding-left: 1.5rem; +} + +.stTabs [data-baseweb="tab-panel"] li { + color: #2D3748; + margin-bottom: 0.5rem; + line-height: 1.6; +} + +/* Tab content headings */ +.stTabs [data-baseweb="tab-panel"] strong { + color: #1A202C; + font-weight: 600; + font-size: 16px; +} + +/* Success/Warning messages in tabs */ +.stTabs [data-baseweb="tab-panel"] .stSuccess, +.stTabs [data-baseweb="tab-panel"] .stWarning { + margin-top: 1rem; + margin-bottom: 1rem; + border-radius: 8px; +} + +/* Main Application Tabs */ +.tab-container { + background: linear-gradient(135deg, #1A202C, #2D3748); + border-radius: 16px; + padding: 20px; + margin: 20px 0; + box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15); +} + +.tab-content { + background: linear-gradient(135deg, #FFFFFF, #F8FAFC); + border-radius: 12px; + padding: 25px; + margin-top: 15px; + border: 1px solid rgba(226, 232, 240, 0.8); + box-shadow: 0 6px 12px rgba(0, 0, 0, 0.05); +} + +/* Tab Content Typography */ +.tab-content h1, .tab-content h2, .tab-content h3 { + color: #2D3748; + margin-bottom: 1rem; + font-weight: 600; +} + +.tab-content p { + color: #4A5568; + line-height: 1.8; + margin-bottom: 1rem; +} + +/* Custom Scrollbar for Tab Content */ +.tab-content::-webkit-scrollbar { + width: 8px; +} + +.tab-content::-webkit-scrollbar-track { + background: #F7FAFC; + border-radius: 4px; +} + +.tab-content::-webkit-scrollbar-thumb { + background: linear-gradient(135deg, #CBD5E0, #A0AEC0); + border-radius: 4px; +} + +.tab-content::-webkit-scrollbar-thumb:hover { + background: linear-gradient(135deg, #A0AEC0, #718096); +} + +/* Enhanced Tab Indicators */ +.stTabs [data-baseweb="tab"][aria-selected="true"]::before { + content: ''; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + background: rgba(255, 255, 255, 0.1); + border-radius: 8px; + z-index: -1; + animation: tabPulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite; +} + +@keyframes tabPulse { + 0%, 100% { opacity: 0.5; } + 50% { opacity: 1; } +} + +/* Text Inputs */ +.stTextInput > div { + background: #FFFFFF; +} + +.stTextInput > div > div > input { + background: #F7FAFC; + border: 2px solid #E2E8F0; + border-radius: 10px; + padding: 12px 16px; + font-size: 15px; + color: #2D3748; + transition: all 0.3s ease; +} + +.stTextInput > div > div > input:hover { + border-color: #CBD5E0; + background: #EDF2F7; +} + +.stTextInput > div > div > input:focus { + border-color: #C53030; + box-shadow: 0 0 0 3px rgba(197, 48, 48, 0.2); + background: #FFFFFF; +} + +/* Sidebar container styling - subtle modern gradient */ +[data-testid="stSidebar"] { + background: linear-gradient(135deg, #f8fafc, #f1f5f9); + color: #334155; + padding: 20px; + border-right: 1px solid rgba(148, 163, 184, 0.2); + box-shadow: 2px 0 8px rgba(0, 0, 0, 0.05); + transition: width 0.3s ease-in-out !important; +} + +/* Collapsed sidebar styling */ +[data-testid="stSidebar"][aria-expanded="false"] { + margin-left: -21rem; +} + +/* Sidebar title styling - improved contrast */ +[data-testid="stSidebar"] h1, [data-testid="stSidebar"] h2, [data-testid="stSidebar"] h3 { + color: #1e293b; + font-weight: 600; + margin-bottom: 1.5rem; + letter-spacing: 0.02em; + border-bottom: 2px solid #e2e8f0; + padding-bottom: 0.75rem; +} + +/* Sidebar expander styling - modern and subtle */ +[data-testid="stSidebar"] .st-expander { + background: linear-gradient(135deg, #ffffff, #f8fafc); + border: 1px solid #e2e8f0; + border-radius: 8px; + margin-bottom: 1rem; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.03); + overflow: hidden; +} + +[data-testid="stSidebar"] .st-expander > div:first-child { + color: #334155; + font-weight: 600; + padding: 0.875rem 1rem; + background: linear-gradient(135deg, #f8fafc, #f1f5f9); + border-bottom: 1px solid #e2e8f0; +} + +/* Radio button styling - improved visibility */ +[data-testid="stSidebar"] .stRadio > div { + display: flex; + flex-direction: column; + gap: 0.625rem; +} + +[data-testid="stSidebar"] .stRadio > div > label { + background: #ffffff; + color: #334155; + padding: 0.75rem 1rem; + border-radius: 6px; + font-weight: 500; + border: 1px solid #e2e8f0; + transition: all 0.2s ease; +} + +[data-testid="stSidebar"] .stRadio > div > label:hover { + background: linear-gradient(135deg, #f1f5f9, #e2e8f0); + transform: translateY(-1px); + border-color: #cbd5e1; +} + +[data-testid="stSidebar"] .stRadio > div > label[data-selected="true"] { + background: linear-gradient(135deg, #0ea5e9, #0284c7); + color: #ffffff; + border-color: #0284c7; + box-shadow: 0 2px 4px rgba(2, 132, 199, 0.2); +} + +/* Input and select styling - improved contrast */ +[data-testid="stSidebar"] input, [data-testid="stSidebar"] select { + background: #ffffff; + color: #334155; + border: 1px solid #e2e8f0; + border-radius: 6px; + padding: 0.75rem; + font-size: 0.875rem; + margin-bottom: 0.75rem; + transition: all 0.2s ease; +} + +[data-testid="stSidebar"] input:focus, [data-testid="stSidebar"] select:focus { + border-color: #0ea5e9; + box-shadow: 0 0 0 2px rgba(14, 165, 233, 0.1); + outline: none; +} + +/* Button styling - modern and subtle */ +[data-testid="stSidebar"] button { + background: linear-gradient(135deg, #0ea5e9, #0284c7); + color: #ffffff; + border: none; + border-radius: 6px; + padding: 0.75rem 1rem; + font-weight: 500; cursor: pointer; - transition: color 0.3s ease; + transition: all 0.2s ease; } -.sidebar-option:hover { - color: #1976D2; +[data-testid="stSidebar"] button:hover { + background: linear-gradient(135deg, #0284c7, #0369a1); + transform: translateY(-1px); + box-shadow: 0 2px 4px rgba(2, 132, 199, 0.2); +} + +/* Settings button styling */ +[data-testid="stSidebar"] .stButton > button { + background: linear-gradient(135deg, #3182CE, #2C5282); + color: white; + border: none; + padding: 0.75rem 1rem; + font-weight: 600; + border-radius: 8px; + transition: all 0.3s ease; + width: 100%; + margin-bottom: 1rem; +} + +[data-testid="stSidebar"] .stButton > button:hover { + background: linear-gradient(135deg, #2C5282, #1A365D); + transform: translateY(-2px); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} + +/* Scrollbar styling - subtle and modern */ +[data-testid="stSidebar"]::-webkit-scrollbar { + width: 8px; +} + +[data-testid="stSidebar"]::-webkit-scrollbar-track { + background: #f8fafc; +} + +[data-testid="stSidebar"]::-webkit-scrollbar-thumb { + background: #cbd5e1; + border-radius: 4px; + border: 2px solid #f8fafc; +} + +[data-testid="stSidebar"]::-webkit-scrollbar-thumb:hover { + background: #94a3b8; } /* Content section styling */ @@ -86,7 +392,6 @@ body { background-color: #ffffff; } - /* Custom button styling */ div.stButton > button:first-child { background: #1565C0; @@ -203,3 +508,169 @@ select option { padding: 10px; } +/* Content Planning Tools Styling */ +.content-header { + background: linear-gradient(135deg, #f8fafc, #f1f5f9); + padding: 1rem; + border-radius: 2px; + margin-bottom: 2rem; + border: 1px solid rgba(148, 163, 184, 0.2); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05); +} + +.content-header h2 { + color: #1e293b; + font-size: 1rem; + font-weight: 300; + margin-bottom: 0.5rem; +} + +.content-header .subtitle { + color: #475569; + font-size: 1.1rem; + line-height: 1; +} + +.tool-section { + background: white; + padding: 1rem; + border-radius: 2px; + margin-bottom: 1.5rem; + border: 1px solid #e2e8f0; +} + +.tool-section h3 { + color: #1e293b; + font-size: 1.4rem; + font-weight: 600; + margin-bottom: 0.75rem; +} + +.tool-section p { + color: #475569; + font-size: 1rem; + line-height: 1.5; +} + +/* Button styling */ +.stButton > button { + background: linear-gradient(135deg, #3182ce, #2c5282); + color: white; + border: none; + padding: 0.75rem 1.5rem; + font-weight: 600; + border-radius: 8px; + transition: all 0.3s ease; +} + +.stButton > button:hover { + background: linear-gradient(135deg, #2c5282, #1a365d); + transform: translateY(-2px); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} + +/* Search option containers styling */ +.search-option-container { + background: linear-gradient(135deg, #f8fafc, #f1f5f9); + border: 1px solid rgba(148, 163, 184, 0.2); + border-radius: 8px; + padding: 1rem; + margin-bottom: 1rem; + text-align: center; + height: 100%; + transition: all 0.3s ease; +} + +.search-option-container:hover { + transform: translateY(-2px); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); +} + +.search-option-container h4 { + color: #1e293b; + margin-bottom: 0.5rem; +} + +.search-option-container p { + color: #64748b; + margin: 0; +} + +/* Button styling for search options */ +.stButton > button { + background: linear-gradient(135deg, #3182ce, #2c5282); + color: white; + border: none; + padding: 0.5rem 1rem; + font-weight: 600; + border-radius: 6px; + transition: all 0.3s ease; +} + +.stButton > button:disabled { + background: linear-gradient(135deg, #94a3b8, #64748b); + cursor: not-allowed; +} + +.stButton > button:not(:disabled):hover { + background: linear-gradient(135deg, #2c5282, #1e3a8a); + transform: translateY(-1px); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); +} + +/* Search options styling */ +.search-option { + background: linear-gradient(135deg, #f8fafc, #f1f5f9); + border: 1px solid rgba(148, 163, 184, 0.2); + border-radius: 8px; + padding: 1rem; + height: 100%; + transition: all 0.3s ease; + text-align: center; +} + +.search-option:hover { + transform: translateY(-2px); + box-shadow: 0 4px 6px rgba(0, 0, 0, 0.05); +} + +.search-option h4 { + color: #1e293b; + margin-bottom: 0.5rem; + font-weight: 600; +} + +.search-option p { + color: #64748b; + font-size: 0.9em; + margin-bottom: 1rem; +} + +.search-option.active { + border: 2px solid #3182ce; + background: linear-gradient(135deg, #ebf8ff, #e6fffa); +} + +/* Add these to your existing search-option styles */ +.search-option.disabled { + background: linear-gradient(135deg, #f1f5f9, #e2e8f0); + opacity: 0.8; + cursor: not-allowed; + border: 1px solid #cbd5e1; +} + + +.search-option .api-missing { + display: inline-block; + background: #fee2e2; + color: #dc2626; + padding: 2px 8px; + border-radius: 4px; + font-size: 0.8em; + margin-top: 0.5rem; +} + +.search-option.disabled h4, +.search-option.disabled p { + color: #64748b; +} \ No newline at end of file diff --git a/lib/workspace/structured_data_seo.mp4 b/lib/workspace/structured_data_seo.mp4 deleted file mode 100644 index af177027..00000000 Binary files a/lib/workspace/structured_data_seo.mp4 and /dev/null differ 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="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}" -) - -# Set page config -st.set_page_config( - layout="wide", - initial_sidebar_state="collapsed", - menu_items={ - 'Get Help': None, - 'Report a bug': None, - 'About': None - } -) - -def render_ai_research_setup_page(): - """Render the AI Research Setup page.""" - try: - logger.info("Starting AI Research Setup page") - - # Import and render the AI Research Setup component - from lib.utils.api_key_manager.components.ai_research_setup import render_ai_research_setup - render_ai_research_setup() - - except Exception as e: - logger.error(f"Error in render_ai_research_setup_page: {str(e)}") - st.error(f"An error occurred: {str(e)}") - -if __name__ == "__main__": - render_ai_research_setup_page() \ No newline at end of file diff --git a/pages/personalization_setup.py b/pages/personalization_setup.py deleted file mode 100644 index d35e9930..00000000 --- a/pages/personalization_setup.py +++ /dev/null @@ -1,84 +0,0 @@ -import streamlit as st -import os -import json -from pathlib import Path - -st.set_page_config( - page_title="Personalization Setup", - page_icon="βš™οΈ", - layout="wide" -) - -st.title("Personalization Setup") - -# Initialize session state for active tab if not exists -if 'active_tab' not in st.session_state: - st.session_state.active_tab = "Writing Preferences" - -# Create tabs for different sections -tab1, tab2 = st.tabs(["Writing Preferences", "AI Configuration"]) - -with tab1: - st.write(""" - This section allows you to customize your AI writing experience. - Configure your preferences and settings here. - """) - - # Add your personalization options here - st.subheader("Writing Style Preferences") - tone = st.selectbox( - "Select your preferred writing tone", - ["Professional", "Casual", "Academic", "Creative"] - ) - - st.subheader("Content Preferences") - content_type = st.multiselect( - "Select your preferred content types", - ["Blog Posts", "Articles", "Social Media", "Technical Writing", "Creative Writing"] - ) - - if st.button("Save Preferences"): - st.success("Your preferences have been saved!") - -with tab2: - st.subheader("AI Configuration Settings") - - # Create a form for AI configuration - with st.form("ai_config_form"): - # API Keys - st.text_input("OpenAI API Key", type="password", key="openai_key") - st.text_input("Google API Key", type="password", key="google_key") - st.text_input("SerpAPI Key", type="password", key="serpapi_key") - - # Model Selection - st.selectbox("Select Model", ["gpt-3.5-turbo", "gpt-4"], key="model") - - # Temperature - st.slider("Temperature", 0.0, 2.0, 0.7, 0.1, key="temperature") - - # Max Tokens - st.number_input("Max Tokens", 100, 4000, 2000, 100, key="max_tokens") - - # Submit button - submitted = st.form_submit_button("Save Configuration") - - if submitted: - # Create config directory if it doesn't exist - config_dir = Path("config") - config_dir.mkdir(exist_ok=True) - - # Save configuration - config = { - "openai_key": st.session_state.openai_key, - "google_key": st.session_state.google_key, - "serpapi_key": st.session_state.serpapi_key, - "model": st.session_state.model, - "temperature": st.session_state.temperature, - "max_tokens": st.session_state.max_tokens - } - - config_file = config_dir / "test_config.json" - with open(config_file, "w") as f: - json.dump(config, f, indent=4) - - st.success("Configuration saved 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