Onboarding changes and improvements
This commit is contained in:
@@ -24,6 +24,67 @@ logger.add(
|
|||||||
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{message}</cyan>"
|
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{message}</cyan>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
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]:
|
def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
|
||||||
"""Render the AI research setup step."""
|
"""Render the AI research setup step."""
|
||||||
logger.info("[render_ai_research_setup] Rendering AI research setup component")
|
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:
|
with col1:
|
||||||
st.markdown("### The Usual")
|
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(
|
serpapi_key = st.text_input(
|
||||||
"## Enter 🔎 SerpAPI",
|
"## Enter 🔎 SerpAPI",
|
||||||
|
value=existing_serpapi_key,
|
||||||
type="password",
|
type="password",
|
||||||
key="serpapi_key",
|
key="serpapi_key",
|
||||||
help="Enter your SerpAPI key",
|
help="Enter your SerpAPI key",
|
||||||
placeholder="Access search engine results for research"
|
placeholder="Access search engine results for research"
|
||||||
)
|
)
|
||||||
|
|
||||||
if serpapi_key:
|
if serpapi_key or existing_serpapi_key:
|
||||||
st.markdown("""
|
st.markdown("""
|
||||||
<div class="ai-provider-status status-valid">
|
<div class="ai-provider-status status-valid">
|
||||||
✓ API key configured
|
✓ API key configured
|
||||||
@@ -76,13 +142,14 @@ def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
|
|||||||
|
|
||||||
firecrawl_key = st.text_input(
|
firecrawl_key = st.text_input(
|
||||||
"Enter 🕷️ Firecrawl API Key",
|
"Enter 🕷️ Firecrawl API Key",
|
||||||
|
value=existing_firecrawl_key,
|
||||||
type="password",
|
type="password",
|
||||||
key="firecrawl_key",
|
key="firecrawl_key",
|
||||||
help="Enter your Firecrawl API key",
|
help="Enter your Firecrawl API key",
|
||||||
placeholder="Web content extraction and analysis"
|
placeholder="Web content extraction and analysis"
|
||||||
)
|
)
|
||||||
|
|
||||||
if firecrawl_key:
|
if firecrawl_key or existing_firecrawl_key:
|
||||||
st.markdown("""
|
st.markdown("""
|
||||||
<div class="ai-provider-status status-valid">
|
<div class="ai-provider-status status-valid">
|
||||||
✓ Firecrawl API key configured
|
✓ Firecrawl API key configured
|
||||||
@@ -113,15 +180,20 @@ def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
|
|||||||
with col2:
|
with col2:
|
||||||
st.markdown("### AI Deep Research")
|
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(
|
tavily_key = st.text_input(
|
||||||
"Enter 🤖 Tavily API Key",
|
"Enter 🤖 Tavily API Key",
|
||||||
|
value=existing_tavily_key,
|
||||||
type="password",
|
type="password",
|
||||||
key="tavily_key",
|
key="tavily_key",
|
||||||
help="Enter your Tavily API key",
|
help="Enter your Tavily API key",
|
||||||
placeholder="AI-powered search with semantic understanding"
|
placeholder="AI-powered search with semantic understanding"
|
||||||
)
|
)
|
||||||
|
|
||||||
if tavily_key:
|
if tavily_key or existing_tavily_key:
|
||||||
st.markdown("""
|
st.markdown("""
|
||||||
<div class="ai-provider-status status-valid">
|
<div class="ai-provider-status status-valid">
|
||||||
✓ Tavily API key configured
|
✓ 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(
|
metaphor_key = st.text_input(
|
||||||
"Enter 🧠 Metaphor/Exa API Key",
|
"Enter 🧠 Metaphor/Exa API Key",
|
||||||
|
value=existing_metaphor_key,
|
||||||
type="password",
|
type="password",
|
||||||
key="metaphor_key",
|
key="metaphor_key",
|
||||||
help="Enter your Metaphor/Exa API key",
|
help="Enter your Metaphor/Exa API key",
|
||||||
placeholder="Neural search engine for deep research"
|
placeholder="Neural search engine for deep research"
|
||||||
)
|
)
|
||||||
|
|
||||||
if metaphor_key:
|
if metaphor_key or existing_metaphor_key:
|
||||||
st.markdown("""
|
st.markdown("""
|
||||||
<div class="ai-provider-status status-valid">
|
<div class="ai-provider-status status-valid">
|
||||||
✓ API key configured
|
✓ 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 render_navigation_buttons(3, 5, changes_made):
|
||||||
if changes_made:
|
if changes_made:
|
||||||
try:
|
try:
|
||||||
# Load existing .env file if it exists
|
# Prepare API keys dictionary with only non-empty values
|
||||||
load_dotenv()
|
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
|
# Update .env file with new API keys
|
||||||
with open('.env', 'a') as f:
|
update_env_file(api_keys)
|
||||||
if serpapi_key:
|
|
||||||
f.write(f"\nSERPAPI_KEY={serpapi_key}")
|
# Update environment variables
|
||||||
logger.info("[render_ai_research_setup] Saved SerpAPI key")
|
for key, value in api_keys.items():
|
||||||
if tavily_key:
|
os.environ[key] = value
|
||||||
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")
|
|
||||||
|
|
||||||
# Store the API keys in session state
|
# Store the API keys in session state
|
||||||
st.session_state['api_keys'] = {
|
st.session_state['api_keys'] = {
|
||||||
|
|||||||
@@ -7,6 +7,42 @@ from typing import Dict, Any
|
|||||||
from ..manager import APIKeyManager
|
from ..manager import APIKeyManager
|
||||||
from .base import render_navigation_buttons, render_step_indicator, render_tab_style
|
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]:
|
def render_alwrity_integrations(api_key_manager: APIKeyManager) -> Dict[str, Any]:
|
||||||
"""Render the ALwrity integrations setup step."""
|
"""Render the ALwrity integrations setup step."""
|
||||||
try:
|
try:
|
||||||
@@ -151,29 +187,33 @@ def render_alwrity_integrations(api_key_manager: APIKeyManager) -> Dict[str, Any
|
|||||||
# Navigation buttons
|
# Navigation buttons
|
||||||
if render_navigation_buttons(5, 6, changes_made):
|
if render_navigation_buttons(5, 6, changes_made):
|
||||||
if has_valid_integrations:
|
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:
|
try:
|
||||||
with open('.env', 'a') as f:
|
# Store integration settings in session state
|
||||||
f.write("\nINTEGRATION_DONE=True")
|
st.session_state['integrations'] = {
|
||||||
os.environ['INTEGRATION_DONE'] = "True"
|
'coming_soon': {
|
||||||
logger.info("Set INTEGRATION_DONE=True in .env and environment")
|
'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:
|
except Exception as e:
|
||||||
logger.error(f"Failed to set INTEGRATION_DONE: {str(e)}")
|
error_msg = f"Failed to update integration status: {str(e)}"
|
||||||
|
logger.error(error_msg)
|
||||||
# Update progress and move to next step
|
st.error(error_msg)
|
||||||
st.session_state['current_step'] = 6
|
|
||||||
st.rerun()
|
|
||||||
else:
|
else:
|
||||||
st.error("Please configure at least one integration to continue")
|
st.error("Please configure at least one integration to continue")
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import os
|
|||||||
logger.remove() # Remove default handler
|
logger.remove() # Remove default handler
|
||||||
logger.add(
|
logger.add(
|
||||||
"logs/website_setup.log",
|
"logs/website_setup.log",
|
||||||
rotation="500 MB",
|
rotation="50 MB",
|
||||||
retention="10 days",
|
retention="10 days",
|
||||||
level="DEBUG",
|
level="DEBUG",
|
||||||
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}"
|
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}"
|
||||||
@@ -26,6 +26,9 @@ logger.add(
|
|||||||
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{message}</cyan>"
|
format="<green>{time:YYYY-MM-DD HH:mm:ss}</green> | <level>{level: <8}</level> | <cyan>{message}</cyan>"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Ensure logs directory exists
|
||||||
|
os.makedirs("logs", exist_ok=True)
|
||||||
|
|
||||||
def render_website_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
|
def render_website_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
|
||||||
"""Render the website setup step.
|
"""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])
|
col1, col2 = st.columns([1, 1])
|
||||||
|
|
||||||
with col1:
|
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}")
|
logger.info(f"[render_website_setup] URL input value: {url}")
|
||||||
|
|
||||||
# Save URL to .env file
|
# Save URL to .env file
|
||||||
try:
|
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:
|
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
|
os.environ['WEBSITE_URL'] = url
|
||||||
logger.info(f"[render_website_setup] Saved website URL to .env: {url}")
|
logger.info(f"[render_website_setup] Saved website URL to .env: {url}")
|
||||||
else:
|
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"
|
os.environ['WEBSITE_URL'] = "no_website_provided"
|
||||||
logger.info("[render_website_setup] Set default website URL: no_website_provided")
|
logger.info("[render_website_setup] Set default website URL: no_website_provided")
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"[render_website_setup] Failed to save website URL: {str(e)}")
|
logger.error(f"[render_website_setup] Failed to save website URL: {str(e)}")
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"Blog Content Characteristics": {
|
"Blog Content Characteristics": {
|
||||||
"Blog Length": "2000",
|
"Blog Length": "2000",
|
||||||
"Blog Tone": "Casual",
|
"Blog Tone": "Professional",
|
||||||
"Blog Demographic": "Professional",
|
"Blog Demographic": "Professional",
|
||||||
"Blog Type": "Informational",
|
"Blog Type": "Informational",
|
||||||
"Blog Language": "English",
|
"Blog Language": "English",
|
||||||
@@ -9,16 +9,14 @@
|
|||||||
},
|
},
|
||||||
"Blog Images Details": {
|
"Blog Images Details": {
|
||||||
"Image Generation Model": "stable-diffusion",
|
"Image Generation Model": "stable-diffusion",
|
||||||
"Number of Blog Images": 1
|
"Number of Blog Images": 1,
|
||||||
|
"Image Style": "Realistic"
|
||||||
},
|
},
|
||||||
"LLM Options": {
|
"LLM Options": {
|
||||||
"GPT Provider": "google",
|
"GPT Provider": "google",
|
||||||
"Model": "gemini-1.5-flash-latest",
|
"Model": "gemini-1.5-flash-latest",
|
||||||
"Temperature": 0.7,
|
"Temperature": 0.7,
|
||||||
"Top-p": 0.9,
|
"Max Tokens": 4000
|
||||||
"Max Tokens": 4000,
|
|
||||||
"Frequency Penalty": 1.0,
|
|
||||||
"Presence Penalty": 1.0
|
|
||||||
},
|
},
|
||||||
"Search Engine Parameters": {
|
"Search Engine Parameters": {
|
||||||
"Geographic Location": "us",
|
"Geographic Location": "us",
|
||||||
|
|||||||
Reference in New Issue
Block a user