From ef462f05f278c191cb0564e1951cf653829c6cec Mon Sep 17 00:00:00 2001 From: ajaysi Date: Fri, 25 Apr 2025 11:28:11 +0530 Subject: [PATCH] Onboarding changes and improvements --- .../components/ai_research_setup.py | 113 ++++++++++++++---- .../components/alwrity_integrations.py | 82 +++++++++---- .../components/website_setup.py | 64 ++++++++-- lib/workspace/alwrity_config/main_config.json | 10 +- 4 files changed, 213 insertions(+), 56 deletions(-) diff --git a/lib/utils/api_key_manager/components/ai_research_setup.py b/lib/utils/api_key_manager/components/ai_research_setup.py index 1c81b394..8b71e4fa 100644 --- a/lib/utils/api_key_manager/components/ai_research_setup.py +++ b/lib/utils/api_key_manager/components/ai_research_setup.py @@ -24,6 +24,67 @@ logger.add( format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}" ) +def get_existing_api_key(key_name: str) -> str: + """Get existing API key from environment or .env file. + + Args: + key_name (str): Name of the API key to retrieve + + Returns: + str: The API key value if found, empty string otherwise + """ + # First try to get from environment + api_key = os.getenv(key_name) + + # If not in environment, try to get from .env file + if not api_key and os.path.exists('.env'): + try: + with open('.env', 'r') as f: + for line in f: + if line.strip().startswith(f"{key_name}="): + api_key = line.strip().split('=')[1] + break + except Exception as e: + logger.error(f"[get_existing_api_key] Failed to read {key_name} from .env: {str(e)}") + + return api_key if api_key else "" + +def update_env_file(api_keys: Dict[str, str]) -> None: + """Update the .env file with new API keys, avoiding duplicates. + + Args: + api_keys (Dict[str, str]): Dictionary of API keys to update + """ + try: + # Read existing .env file content + env_content = [] + if os.path.exists('.env'): + with open('.env', 'r') as f: + env_content = f.readlines() + + # Remove trailing newlines and empty lines + env_content = [line.strip() for line in env_content if line.strip()] + + # Create a dictionary of existing variables + env_dict = {} + for line in env_content: + if '=' in line: + key, value = line.split('=', 1) + env_dict[key.strip()] = value.strip() + + # Update with new values + env_dict.update(api_keys) + + # Write back to .env file + with open('.env', 'w') as f: + for key, value in env_dict.items(): + f.write(f"{key}={value}\n") + + logger.info("[update_env_file] Successfully updated .env file with API keys") + except Exception as e: + logger.error(f"[update_env_file] Error updating .env file: {str(e)}") + raise + def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]: """Render the AI research setup step.""" logger.info("[render_ai_research_setup] Rendering AI research setup component") @@ -38,15 +99,20 @@ def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]: with col1: st.markdown("### The Usual") + # Get existing API keys + existing_serpapi_key = get_existing_api_key("SERPAPI_KEY") + existing_firecrawl_key = get_existing_api_key("FIRECRAWL_API_KEY") + serpapi_key = st.text_input( "## Enter 🔎 SerpAPI", + value=existing_serpapi_key, type="password", key="serpapi_key", help="Enter your SerpAPI key", placeholder="Access search engine results for research" ) - if serpapi_key: + if serpapi_key or existing_serpapi_key: st.markdown("""
✓ API key configured @@ -76,13 +142,14 @@ def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]: firecrawl_key = st.text_input( "Enter 🕷️ Firecrawl API Key", + value=existing_firecrawl_key, type="password", key="firecrawl_key", help="Enter your Firecrawl API key", placeholder="Web content extraction and analysis" ) - if firecrawl_key: + if firecrawl_key or existing_firecrawl_key: st.markdown("""
✓ Firecrawl API key configured @@ -113,15 +180,20 @@ def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]: with col2: st.markdown("### AI Deep Research") + # Get existing API keys + existing_tavily_key = get_existing_api_key("TAVILY_API_KEY") + existing_metaphor_key = get_existing_api_key("METAPHOR_API_KEY") + tavily_key = st.text_input( "Enter 🤖 Tavily API Key", + value=existing_tavily_key, type="password", key="tavily_key", help="Enter your Tavily API key", placeholder="AI-powered search with semantic understanding" ) - if tavily_key: + if tavily_key or existing_tavily_key: st.markdown("""
✓ Tavily API key configured @@ -151,13 +223,14 @@ def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]: metaphor_key = st.text_input( "Enter 🧠 Metaphor/Exa API Key", + value=existing_metaphor_key, type="password", key="metaphor_key", help="Enter your Metaphor/Exa API key", placeholder="Neural search engine for deep research" ) - if metaphor_key: + if metaphor_key or existing_metaphor_key: st.markdown("""
✓ API key configured @@ -194,23 +267,23 @@ def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]: if render_navigation_buttons(3, 5, changes_made): if changes_made: try: - # Load existing .env file if it exists - load_dotenv() + # Prepare API keys dictionary with only non-empty values + api_keys = {} + if serpapi_key: + api_keys['SERPAPI_KEY'] = serpapi_key + if tavily_key: + api_keys['TAVILY_API_KEY'] = tavily_key + if metaphor_key: + api_keys['METAPHOR_API_KEY'] = metaphor_key + if firecrawl_key: + api_keys['FIRECRAWL_API_KEY'] = firecrawl_key - # Create or update .env file with new API keys - with open('.env', 'a') as f: - if serpapi_key: - f.write(f"\nSERPAPI_KEY={serpapi_key}") - logger.info("[render_ai_research_setup] Saved SerpAPI key") - if tavily_key: - f.write(f"\nTAVILY_API_KEY={tavily_key}") - logger.info("[render_ai_research_setup] Saved Tavily API key") - if metaphor_key: - f.write(f"\nMETAPHOR_API_KEY={metaphor_key}") - logger.info("[render_ai_research_setup] Saved Metaphor API key") - if firecrawl_key: - f.write(f"\nFIRECRAWL_API_KEY={firecrawl_key}") - logger.info("[render_ai_research_setup] Saved Firecrawl API key") + # Update .env file with new API keys + update_env_file(api_keys) + + # Update environment variables + for key, value in api_keys.items(): + os.environ[key] = value # Store the API keys in session state st.session_state['api_keys'] = { diff --git a/lib/utils/api_key_manager/components/alwrity_integrations.py b/lib/utils/api_key_manager/components/alwrity_integrations.py index 9f11b2e1..adf00eaf 100644 --- a/lib/utils/api_key_manager/components/alwrity_integrations.py +++ b/lib/utils/api_key_manager/components/alwrity_integrations.py @@ -7,6 +7,42 @@ from typing import Dict, Any from ..manager import APIKeyManager from .base import render_navigation_buttons, render_step_indicator, render_tab_style +def update_env_file(env_vars: Dict[str, str]) -> None: + """Update the .env file with new environment variables, avoiding duplicates. + + Args: + env_vars (Dict[str, str]): Dictionary of environment variables to update + """ + try: + # Read existing .env file content + env_content = [] + if os.path.exists('.env'): + with open('.env', 'r') as f: + env_content = f.readlines() + + # Remove trailing newlines and empty lines + env_content = [line.strip() for line in env_content if line.strip()] + + # Create a dictionary of existing variables + env_dict = {} + for line in env_content: + if '=' in line: + key, value = line.split('=', 1) + env_dict[key.strip()] = value.strip() + + # Update with new values + env_dict.update(env_vars) + + # Write back to .env file + with open('.env', 'w') as f: + for key, value in env_dict.items(): + f.write(f"{key}={value}\n") + + logger.info("[update_env_file] Successfully updated .env file") + except Exception as e: + logger.error(f"[update_env_file] Error updating .env file: {str(e)}") + raise + def render_alwrity_integrations(api_key_manager: APIKeyManager) -> Dict[str, Any]: """Render the ALwrity integrations setup step.""" try: @@ -151,29 +187,33 @@ def render_alwrity_integrations(api_key_manager: APIKeyManager) -> Dict[str, Any # Navigation buttons if render_navigation_buttons(5, 6, changes_made): if has_valid_integrations: - # Store integration settings in session state - st.session_state['integrations'] = { - 'coming_soon': { - 'wordpress': True, - 'wix': True, - 'facebook': True, - 'instagram': True, - 'google_search_console': True - } - } - - # Set INTEGRATION_DONE to True in .env file and environment try: - with open('.env', 'a') as f: - f.write("\nINTEGRATION_DONE=True") - os.environ['INTEGRATION_DONE'] = "True" - logger.info("Set INTEGRATION_DONE=True in .env and environment") + # Store integration settings in session state + st.session_state['integrations'] = { + 'coming_soon': { + 'wordpress': True, + 'wix': True, + 'facebook': True, + 'instagram': True, + 'google_search_console': True + } + } + + # Update INTEGRATION_DONE in .env file and environment + env_vars = {'INTEGRATION_DONE': 'True'} + update_env_file(env_vars) + + # Update environment variable + os.environ['INTEGRATION_DONE'] = 'True' + logger.info("Updated INTEGRATION_DONE status") + + # Update progress and move to next step + st.session_state['current_step'] = 6 + st.rerun() except Exception as e: - logger.error(f"Failed to set INTEGRATION_DONE: {str(e)}") - - # Update progress and move to next step - st.session_state['current_step'] = 6 - st.rerun() + error_msg = f"Failed to update integration status: {str(e)}" + logger.error(error_msg) + st.error(error_msg) else: st.error("Please configure at least one integration to continue") diff --git a/lib/utils/api_key_manager/components/website_setup.py b/lib/utils/api_key_manager/components/website_setup.py index ff260ee7..278da58c 100644 --- a/lib/utils/api_key_manager/components/website_setup.py +++ b/lib/utils/api_key_manager/components/website_setup.py @@ -15,7 +15,7 @@ import os logger.remove() # Remove default handler logger.add( "logs/website_setup.log", - rotation="500 MB", + rotation="50 MB", retention="10 days", level="DEBUG", format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}" @@ -26,6 +26,9 @@ logger.add( format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}" ) +# Ensure logs directory exists +os.makedirs("logs", exist_ok=True) + def render_website_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]: """Render the website setup step. @@ -43,24 +46,67 @@ def render_website_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]: col1, col2 = st.columns([1, 1]) with col1: - url = st.text_input("Enter your website URL, if you own one", placeholder="https://example.com") + # Get existing website URL from environment or .env file + existing_url = os.getenv('WEBSITE_URL', None) + if not existing_url and os.path.exists('.env'): + try: + with open('.env', 'r') as f: + for line in f: + if line.strip().startswith('WEBSITE_URL='): + existing_url = line.strip().split('=')[1] + break + except Exception as e: + logger.error(f"[render_website_setup] Failed to read existing URL from .env: {str(e)}") + + # If existing_url is 'no_website_provided', set it to empty for better UX + if existing_url == 'no_website_provided': + existing_url = '' + + url = st.text_input( + "Enter your website URL, if you own one", + value=existing_url if existing_url else "", + placeholder="https://example.com" + ) logger.info(f"[render_website_setup] URL input value: {url}") # Save URL to .env file try: + # Check if WEBSITE_URL already exists in .env file + website_url_exists = False + env_lines = [] + + if os.path.exists('.env'): + with open('.env', 'r') as f: + for line in f: + if line.strip().startswith('WEBSITE_URL='): + website_url_exists = True + # Replace the existing WEBSITE_URL line with the new value + if url: + env_lines.append(f"WEBSITE_URL={url}\n") + else: + env_lines.append("WEBSITE_URL=no_website_provided\n") + else: + env_lines.append(line) + + # If WEBSITE_URL doesn't exist, add it + if not website_url_exists: + if url: + env_lines.append(f"WEBSITE_URL={url}\n") + else: + env_lines.append("WEBSITE_URL=no_website_provided\n") + + # Write all lines back to the .env file + with open('.env', 'w') as f: + f.writelines(env_lines) + + # Set environment variable if url: - # Save to .env file - with open('.env', 'a') as f: - f.write(f"\nWEBSITE_URL={url}") - # Set environment variable os.environ['WEBSITE_URL'] = url logger.info(f"[render_website_setup] Saved website URL to .env: {url}") else: - # Set default value if no URL provided - with open('.env', 'a') as f: - f.write("\nWEBSITE_URL=no_website_provided") os.environ['WEBSITE_URL'] = "no_website_provided" logger.info("[render_website_setup] Set default website URL: no_website_provided") + except Exception as e: logger.error(f"[render_website_setup] Failed to save website URL: {str(e)}") diff --git a/lib/workspace/alwrity_config/main_config.json b/lib/workspace/alwrity_config/main_config.json index cbe9e4b9..dbed441a 100644 --- a/lib/workspace/alwrity_config/main_config.json +++ b/lib/workspace/alwrity_config/main_config.json @@ -1,7 +1,7 @@ { "Blog Content Characteristics": { "Blog Length": "2000", - "Blog Tone": "Casual", + "Blog Tone": "Professional", "Blog Demographic": "Professional", "Blog Type": "Informational", "Blog Language": "English", @@ -9,16 +9,14 @@ }, "Blog Images Details": { "Image Generation Model": "stable-diffusion", - "Number of Blog Images": 1 + "Number of Blog Images": 1, + "Image Style": "Realistic" }, "LLM Options": { "GPT Provider": "google", "Model": "gemini-1.5-flash-latest", "Temperature": 0.7, - "Top-p": 0.9, - "Max Tokens": 4000, - "Frequency Penalty": 1.0, - "Presence Penalty": 1.0 + "Max Tokens": 4000 }, "Search Engine Parameters": { "Geographic Location": "us",