Fix environment variable handling in setup: PERSONALIZATION_DONE and FINAL_SETUP_COMPLETE

This commit is contained in:
ajaysi
2025-04-25 11:27:17 +05:30
parent 92b433bf9a
commit b9359b04fb
2 changed files with 378 additions and 595 deletions

View File

@@ -192,6 +192,49 @@ def render_final_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
if st.button("Complete Setup →"):
logger.info("[render_final_setup] User clicked complete setup")
try:
# First set FINAL_SETUP_COMPLETE to True
try:
# Read existing .env content
env_lines = []
if os.path.exists('.env'):
with open('.env', 'r') as f:
env_lines = f.readlines()
# Remove any existing FINAL_SETUP_COMPLETE entries
env_lines = [line for line in env_lines if not line.startswith('FINAL_SETUP_COMPLETE=')]
# Add the new FINAL_SETUP_COMPLETE entry
env_lines.append("FINAL_SETUP_COMPLETE=True\n")
# Write back to .env file
with open('.env', 'w') as f:
f.writelines(env_lines)
# Set environment variable
os.environ['FINAL_SETUP_COMPLETE'] = "True"
logger.info("[render_final_setup] Set FINAL_SETUP_COMPLETE=True")
except Exception as e:
logger.error(f"[render_final_setup] Error setting FINAL_SETUP_COMPLETE: {str(e)}")
st.error("Error updating setup status. Please try again.")
return {"current_step": 6, "changes_made": False}
# Now validate all steps
validation_result = check_all_api_keys(api_key_manager)
if not validation_result:
# If validation fails, revert FINAL_SETUP_COMPLETE
try:
env_lines = [line for line in env_lines if not line.startswith('FINAL_SETUP_COMPLETE=')]
env_lines.append("FINAL_SETUP_COMPLETE=False\n")
with open('.env', 'w') as f:
f.writelines(env_lines)
os.environ['FINAL_SETUP_COMPLETE'] = "False"
except Exception:
pass # Ignore reversion errors
st.error("Setup validation failed. Please ensure all required steps are completed.")
logger.error("[render_final_setup] Validation failed")
return {"current_step": 6, "changes_made": False}
# Log the current API keys in the manager
logger.info("[render_final_setup] Current API keys in manager:")
for key, value in api_key_manager.api_keys.items():
@@ -200,46 +243,30 @@ def render_final_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
else:
logger.info(f" - {key}: Not set")
# Log environment variables
logger.info("[render_final_setup] Checking environment variables:")
for key in os.environ.keys():
if any(provider in key for provider in ['API_KEY', 'SERPAPI', 'TAVILY', 'METAPHOR', 'FIRECRAWL']):
value = os.getenv(key)
if value:
logger.info(f" - {key}: {'*' * 8}{value[-4:]}")
else:
logger.error(f" - {key}: Not set")
# Save main configuration
config_path = os.path.join("lib", "workspace", "alwrity_config", "main_config.json")
with open(config_path, 'w') as f:
json.dump(main_config, f, indent=4)
logger.info("[render_final_setup] Saved main configuration")
# Set FINAL_SETUP_COMPLETE to True in .env file and environment
try:
with open('.env', 'a') as f:
f.write("\nFINAL_SETUP_COMPLETE=True")
os.environ['FINAL_SETUP_COMPLETE'] = "True"
logger.info("Set FINAL_SETUP_COMPLETE=True in .env and environment")
except Exception as e:
logger.error(f"Failed to set FINAL_SETUP_COMPLETE: {str(e)}")
# Show success message with HTML formatting
st.markdown("""
<div style='background-color: #d4edda; color: #155724; padding: 1rem; border-radius: 0.25rem;'>
<h4 style='margin: 0;'>✅ Setup Completed Successfully!</h4>
<p style='margin: 0.5rem 0 0;'>Your configuration has been saved and you're ready to use ALwrity.</p>
</div>
""", unsafe_allow_html=True)
# Show success message
st.success("✅ Setup completed successfully! Redirecting to main application...")
# Set setup completion flag in session state
st.session_state['setup_completed'] = True
st.session_state['redirect_to_main'] = True
# Redirect to main application
# Clear the current step to ensure proper redirection
if 'current_step' in st.session_state:
del st.session_state['current_step']
# Rerun to trigger redirection
st.rerun()
except Exception as e:
error_msg = f"Error completing setup: {str(e)}"
logger.error(f"[render_final_setup] {error_msg}")
st.error(error_msg)
return {"current_step": 6, "changes_made": False}
return {"current_step": 6, "changes_made": True}

View File

@@ -122,610 +122,366 @@ def render_personalization_setup(api_key_manager: APIKeyManager) -> Dict[str, An
logger.info("[render_personalization_setup] Rendering personalization setup component")
st.markdown("""
<div class='setup-header'>
<h2>✨ Personalization Setup</h2>
<p>Configure your content generation preferences and writing style</p>
</div>
""", unsafe_allow_html=True)
# ✨ Personalization Setup
Configure your content generation preferences and writing style
""")
# Load main config
main_config = load_main_config()
# Main section selection using radio buttons
setup_mode = st.radio(
"Choose Setup Mode",
["Manual Settings", "ALwrity Personalization"],
horizontal=True,
label_visibility="collapsed"
)
# Create tabs for different personalization methods
tab1, tab2 = st.tabs([
"Manual Settings",
"ALwrity Personalization"
])
with tab1:
st.markdown("### Manual Settings Configuration")
if setup_mode == "Manual Settings":
# Create tabs for different settings categories
tabs = st.tabs([
"Blog Content Characteristics",
"Blog Images",
"AI Generation Settings",
"Search Settings"
])
# Add container for better width control
st.markdown("""
<div style='width: 100%; max-width: 100%; margin: 0; padding: 0;'>
""", unsafe_allow_html=True)
# Create two columns for settings and explanations (1:2 ratio)
settings_col, info_col = st.columns([1, 2])
with settings_col:
st.markdown("""
<div style='padding-right: 2rem;'>
""", unsafe_allow_html=True)
# Blog Content Characteristics Tab
with tabs[0]:
col1, col2 = st.columns([1, 1])
# Blog Content Characteristics
st.markdown("#### Blog Content Characteristics")
blog_settings = main_config.get("Blog Content Characteristics", {})
with col1:
st.markdown("#### Blog Content Characteristics")
blog_length = st.text_input(
"Blog Length",
value="2000",
placeholder="e.g., 2000",
help="Target word count for your blog posts"
)
blog_tone = st.selectbox(
"Blog Tone",
["Professional", "Casual", "Technical", "Conversational"],
help="The overall tone of your content"
)
blog_demographic = st.selectbox(
"Target Demographic",
["Professional", "General", "Technical", "Academic"],
help="Your primary audience demographic"
)
blog_type = st.selectbox(
"Content Type",
["Informational", "Educational", "Entertainment", "Technical"],
help="The primary type of content you create"
)
blog_language = st.selectbox(
"Content Language",
["English", "Spanish", "French", "German", "Other"],
help="Primary language for your content"
)
blog_format = st.selectbox(
"Output Format",
["markdown", "html", "plain text"],
help="Format of the generated content"
)
blog_length = st.text_input(
"Blog Length",
value=blog_settings.get("Blog Length", "2000"),
placeholder="e.g., 2000",
help="Target word count for your blog posts"
)
blog_tone = st.selectbox(
"Blog Tone",
options=["Professional", "Casual", "Technical", "Conversational"],
index=["Professional", "Casual", "Technical", "Conversational"].index(blog_settings.get("Blog Tone", "Professional")),
help="The overall tone of your content"
)
blog_demographic = st.selectbox(
"Target Demographic",
options=["Professional", "General", "Technical", "Academic"],
index=["Professional", "General", "Technical", "Academic"].index(blog_settings.get("Blog Demographic", "Professional")),
help="Your primary audience demographic"
)
blog_type = st.selectbox(
"Content Type",
options=["Informational", "Educational", "Entertainment", "Technical"],
index=["Informational", "Educational", "Entertainment", "Technical"].index(blog_settings.get("Blog Type", "Informational")),
help="The primary type of content you create"
)
blog_language = st.selectbox(
"Content Language",
options=["English", "Spanish", "French", "German", "Other"],
index=["English", "Spanish", "French", "German", "Other"].index(blog_settings.get("Blog Language", "English")),
help="Primary language for your content"
)
blog_format = st.selectbox(
"Output Format",
options=["markdown", "html", "plain text"],
index=["markdown", "html", "plain text"].index(blog_settings.get("Blog Output Format", "markdown")),
help="Format of the generated content"
)
# Blog Images Details
st.markdown("#### Blog Images")
image_settings = main_config.get("Blog Images Details", {})
image_model = st.selectbox(
"Image Generation Model",
options=["stable-diffusion", "dall-e", "midjourney"],
index=["stable-diffusion", "dall-e", "midjourney"].index(image_settings.get("Image Generation Model", "stable-diffusion")),
help="AI model for generating images"
)
num_images = st.number_input(
"Number of Images",
min_value=1,
max_value=5,
value=image_settings.get("Number of Blog Images", 1),
help="Number of images to generate per blog post"
)
# LLM Options
st.markdown("#### AI Generation Settings")
llm_settings = main_config.get("LLM Options", {})
gpt_provider = st.selectbox(
"AI Provider",
options=["google", "openai", "anthropic"],
index=["google", "openai", "anthropic"].index(llm_settings.get("GPT Provider", "google")),
help="Choose your preferred AI provider"
)
model = st.text_input(
"Model",
value=llm_settings.get("Model", "gemini-1.5-flash-latest"),
placeholder="e.g., gemini-1.5-flash-latest",
help="The specific AI model to use"
)
temperature = st.slider(
"Creativity Level",
min_value=0.0,
max_value=1.0,
value=float(llm_settings.get("Temperature", 0.7)),
help="Higher values = more creative, lower values = more focused"
)
top_p = st.slider(
"Output Diversity",
min_value=0.0,
max_value=1.0,
value=float(llm_settings.get("Top-p", 0.9)),
help="Controls diversity of generated content"
)
max_tokens = st.number_input(
"Maximum Length",
min_value=100,
max_value=8000,
value=int(llm_settings.get("Max Tokens", 4000)),
help="Maximum length of generated content"
)
frequency_penalty = st.slider(
"Frequency Penalty",
min_value=-2.0,
max_value=2.0,
value=float(llm_settings.get("Frequency Penalty", 1.0)),
help="Reduces repetition of the same words"
)
presence_penalty = st.slider(
"Presence Penalty",
min_value=-2.0,
max_value=2.0,
value=float(llm_settings.get("Presence Penalty", 1.0)),
help="Encourages discussion of new topics"
)
# Search Engine Parameters
st.markdown("#### Search Settings")
search_settings = main_config.get("Search Engine Parameters", {})
geo_location = st.text_input(
"Geographic Location",
value=search_settings.get("Geographic Location", "us"),
placeholder="e.g., us, uk, ca",
help="Target geographic location for search results"
)
search_language = st.selectbox(
"Search Language",
options=["en", "es", "fr", "de", "other"],
index=["en", "es", "fr", "de", "other"].index(search_settings.get("Search Language", "en")),
help="Language for search results"
)
num_results = st.number_input(
"Number of Results",
min_value=1,
max_value=50,
value=search_settings.get("Number of Results", 10),
help="Number of search results to analyze"
)
time_range = st.selectbox(
"Time Range",
options=["anytime", "day", "week", "month", "year"],
index=["anytime", "day", "week", "month", "year"].index(search_settings.get("Time Range", "anytime")),
help="Time range for search results"
)
st.markdown("</div>", unsafe_allow_html=True)
with info_col:
st.markdown("""
<div style='
padding-left: 2rem;
border-left: 2px solid #e0e0e0;
background-color: #f8f9fa;
border-radius: 0 8px 8px 0;
margin: -1rem 0;
padding-top: 1rem;
padding-bottom: 1rem;
'>
""", unsafe_allow_html=True)
st.markdown("""
<div style='padding: 0 1rem;'>
### Understanding Your Settings
#### Blog Content Settings
**Blog Length**
- Determines the target word count for your posts
- Affects content depth and detail level
- Impacts reader engagement and SEO performance
- Recommended: 1500-2500 words for comprehensive coverage
**Blog Tone**
- Professional: Formal, business-oriented, authoritative
- Casual: Friendly, conversational, approachable
- Technical: Detailed, precise, industry-specific
- Conversational: Engaging, relatable, personal
**Target Demographic**
- Professional: Business audience, decision-makers
- General: Broad readership, general public
- Technical: Specialized audience, industry experts
- Academic: Research-focused, scholarly readers
**Content Type**
- Informational: Facts, insights, and analysis
- Educational: Teaching, tutorials, how-to guides
- Entertainment: Engaging, fun, light content
- Technical: Detailed analysis, specifications
**Content Language**
- Select your primary content language
- Affects grammar, idioms, and cultural context
- Impacts SEO and audience reach
**Output Format**
- Markdown: Best for most platforms
- HTML: For web publishing
- Plain Text: For simple content
#### Image Generation Settings
**Image Generation Model**
- Stable Diffusion: Best for general content
- DALL-E: Great for creative concepts
- Midjourney: Excellent for artistic content
**Number of Images**
- Consider your content type and platform
- More images = better engagement but higher cost
- Recommended: 1-2 images per post
#### AI Generation Settings
**AI Provider**
- Google: Balanced, reliable, cost-effective
- OpenAI: Creative, nuanced, versatile
- Anthropic: Precise, ethical, focused
**Model Selection**
- Latest models offer best performance
- Specialized models for specific needs
- Consider cost vs. quality trade-offs
**Creativity Level (Temperature)**
- 0.0: Focused, consistent, predictable
- 0.5: Balanced creativity and coherence
- 1.0: Maximum creativity, more varied
**Output Diversity (Top-p)**
- Controls variety in word choices
- Higher values = more diverse vocabulary
- Lower values = more focused terminology
**Maximum Length**
- Affects content completeness
- Consider platform limits
- Balance detail vs. readability
**Frequency & Presence Penalties**
- Reduce repetition of words
- Encourage topic diversity
- Fine-tune content variety
#### Search Settings
**Geographic Location**
- Target specific regions
- Affects local SEO
- Influences content relevance
**Search Language**
- Match your content language
- Affects result relevance
with col2:
st.markdown("### Blog Content Settings Guide")
st.markdown("""
#### Blog Length
- Determines word count target
- Affects content depth
- Impacts SEO performance
**Number of Results**
- More results = better analysis
- Consider processing time
- Balance quality vs. speed
#### Blog Tone
- Professional: Business-oriented
- Casual: Friendly, approachable
- Technical: Detailed, precise
**Time Range**
- Anytime: All available content
- Recent: Latest information
- Historical: Past content
### Best Practices
1. **Start Conservative**
- Begin with moderate settings
- Adjust based on results
- Monitor performance
2. **Consider Your Audience**
- Match tone to reader expectations
- Adjust complexity appropriately
- Focus on value delivery
3. **Optimize for Platform**
- Consider platform limitations
- Match format requirements
- Optimize for engagement
4. **Regular Review**
- Monitor content performance
- Adjust settings as needed
- Stay updated with trends
</div>
""", unsafe_allow_html=True)
st.markdown("</div>", unsafe_allow_html=True)
#### Best Practices
- Match tone to audience
- Consider SEO requirements
- Maintain consistency
""")
# Close the container
st.markdown("</div>", unsafe_allow_html=True)
# Add some spacing before the save button
st.markdown("<div style='height: 1.5rem;'></div>", unsafe_allow_html=True)
if st.button("Save Manual Settings", type="primary", use_container_width=True):
# Update main config with new values
main_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_format
}
# Blog Images Tab
with tabs[1]:
col1, col2 = st.columns([1, 1])
main_config["Blog Images Details"] = {
"Image Generation Model": image_model,
"Number of Blog Images": num_images
}
main_config["LLM Options"] = {
"GPT Provider": gpt_provider,
"Model": model,
"Temperature": temperature,
"Top-p": top_p,
"Max Tokens": max_tokens,
"Frequency Penalty": frequency_penalty,
"Presence Penalty": presence_penalty
}
main_config["Search Engine Parameters"] = {
"Geographic Location": geo_location,
"Search Language": search_language,
"Number of Results": num_results,
"Time Range": time_range
}
if save_main_config(main_config):
# Set PERSONALIZATION_DONE to True in .env file and environment
try:
with open('.env', 'a') as f:
f.write("\nPERSONALIZATION_DONE=True")
os.environ['PERSONALIZATION_DONE'] = "True"
logger.info("Set PERSONALIZATION_DONE=True in .env and environment")
except Exception as e:
logger.error(f"Failed to set PERSONALIZATION_DONE: {str(e)}")
with col1:
st.markdown("#### Blog Images Settings")
st.success("✅ Your personalization settings have been saved successfully!")
else:
st.error("Unable to save settings. Please try again.")
with tab2:
st.markdown("#### ALwrity Personalization")
image_model = st.selectbox(
"Image Generation Model",
["stable-diffusion", "dall-e", "midjourney"],
help="AI model for generating images"
)
num_images = st.number_input(
"Number of Images",
min_value=1,
max_value=5,
value=1,
help="Number of images per blog post"
)
image_style = st.selectbox(
"Image Style",
["Realistic", "Artistic", "Professional", "Creative"],
help="Style of generated images"
)
with col2:
st.markdown("### Image Generation Guide")
st.markdown("""
#### Model Selection
- Stable Diffusion: Versatile, fast
- DALL-E: High quality, creative
- Midjourney: Artistic, detailed
#### Best Practices
- Consider content type
- Balance quality vs. speed
- Optimize for platforms
""")
# Create two columns for the layout
# AI Generation Settings Tab
with tabs[2]:
col1, col2 = st.columns([1, 1])
with col1:
st.markdown("#### AI Generation Settings")
gpt_provider = st.selectbox(
"AI Provider",
["google", "openai", "anthropic"],
help="Choose your preferred AI provider"
)
model = st.text_input(
"Model",
value="gemini-1.5-flash-latest",
help="The specific AI model to use"
)
temperature = st.slider(
"Creativity Level",
min_value=0.0,
max_value=1.0,
value=0.7,
help="Higher = more creative, lower = more focused"
)
max_tokens = st.number_input(
"Maximum Length",
min_value=100,
max_value=8000,
value=4000,
help="Maximum length of generated content"
)
with col2:
st.markdown("### AI Settings Guide")
st.markdown("""
#### Provider Selection
- Google: Balanced, reliable
- OpenAI: Creative, versatile
- Anthropic: Precise, ethical
#### Temperature Guide
- 0.0-0.3: Focused, consistent
- 0.4-0.7: Balanced creativity
- 0.8-1.0: Highly creative
""")
# Search Settings Tab
with tabs[3]:
col1, col2 = st.columns([1, 1])
with col1:
st.markdown("#### Search Settings")
geo_location = st.text_input(
"Geographic Location",
value="us",
help="Target geographic location for search"
)
search_language = st.selectbox(
"Search Language",
["en", "es", "fr", "de", "other"],
help="Language for search results"
)
num_results = st.number_input(
"Number of Results",
min_value=1,
max_value=50,
value=10,
help="Number of search results to analyze"
)
time_range = st.selectbox(
"Time Range",
["anytime", "day", "week", "month", "year"],
help="Time range for search results"
)
with col2:
st.markdown("### Search Settings Guide")
st.markdown("""
#### Location & Language
- Affects result relevance
- Impacts local SEO
- Consider target market
#### Search Optimization
- Balance quantity vs. quality
- Consider time sensitivity
- Optimize for accuracy
""")
# Save button for manual settings
if st.button("Save Manual Settings", type="primary", use_container_width=True):
try:
# Save to main_config.json
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_format
},
"Blog Images Details": {
"Image Generation Model": image_model,
"Number of Blog Images": num_images,
"Image Style": image_style
},
"LLM Options": {
"GPT Provider": gpt_provider,
"Model": model,
"Temperature": temperature,
"Max Tokens": max_tokens
},
"Search Engine Parameters": {
"Geographic Location": geo_location,
"Search Language": search_language,
"Number of Results": num_results,
"Time Range": time_range
}
}
if save_main_config(config):
try:
# Read existing .env file content
env_lines = []
if os.path.exists('.env'):
with open('.env', 'r') as f:
env_lines = f.readlines()
# Remove any existing PERSONALIZATION_DONE entries
env_lines = [line for line in env_lines if not line.startswith('PERSONALIZATION_DONE=')]
# Add new PERSONALIZATION_DONE entry
env_lines.append("PERSONALIZATION_DONE=True\n")
# Write back to .env file
with open('.env', 'w') as f:
f.writelines(env_lines)
# Update environment variable and session state
os.environ['PERSONALIZATION_DONE'] = "True"
st.session_state['personalization_saved'] = True
logger.info("Successfully set PERSONALIZATION_DONE=True in .env and environment")
st.success("✅ Your personalization settings have been saved successfully!")
except Exception as e:
logger.error(f"Error updating PERSONALIZATION_DONE: {str(e)}")
st.error("Settings saved but failed to update environment. Please try again.")
else:
st.error("Unable to save settings. Please try again.")
except Exception as e:
logger.error(f"Error saving settings: {str(e)}")
st.error(f"Failed to save settings: {str(e)}")
else: # ALwrity Personalization
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."
help="Provide your website URL to analyze your content style"
)
logger.debug(f"Website URL input value: {url}")
# Alternative: Written samples
if not url:
st.markdown("### Written Samples")
st.markdown("""
<div style='background-color: #f8f9fa; padding: 1rem; border-radius: 0.5rem; margin: 1rem 0;'>
<p>No website URL? No problem! You can provide written samples of your content instead.</p>
<p>Share your best articles, blog posts, or any content that represents your writing style.</p>
</div>
""", unsafe_allow_html=True)
st.info("No website URL? No problem! Provide written samples instead.")
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."
help="Paste 2-3 samples of your best content"
)
logger.debug(f"Sample text length: {len(samples) if samples else 0}")
# ALwrity Style button
st.markdown("<div style='height: 20px'></div>", 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:
# Initialize style analyzer
style_analyzer = StyleAnalyzer()
# Analyze content samples
style_analysis = style_analyzer.analyze_content_style({"main_content": samples})
if style_analysis.get('error'):
st.error(f"Style analysis failed: {style_analysis['error']}")
else:
# Display style analysis results
display_style_analysis(style_analysis)
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")
if st.button("🎨 Analyze Style", use_container_width=True):
# Existing style analysis code...
pass
with col2:
st.markdown(get_glass_container("""
### 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:
st.markdown("### How ALwrity Discovers Your Style")
st.markdown("""
#### AI-Powered Analysis
ALwrity analyzes your content to understand:
- Writing tone and voice
- Vocabulary and language style
- Content structure and formatting
- Target audience and engagement style
- Content structure
- Target audience
- 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
"""))
# API Configuration Form
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")
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!")
#### Personalized Recommendations
We provide:
- Writing guidelines
- Content templates
- Style recommendations
- Audience insights
""")
# Navigation buttons with correct arguments
# Navigation buttons
if render_navigation_buttons(4, 6, changes_made=True):
# Set PERSONALIZATION_DONE to False if not already set to True
if 'PERSONALIZATION_DONE' not in os.environ or os.environ['PERSONALIZATION_DONE'] != "True":
try:
with open('.env', 'a') as f:
f.write("\nPERSONALIZATION_DONE=False")
try:
# If user hasn't saved settings manually, mark as skipped
if 'personalization_saved' not in st.session_state or not st.session_state.get('personalization_saved'):
# Read existing .env file content
env_lines = []
if os.path.exists('.env'):
with open('.env', 'r') as f:
env_lines = f.readlines()
# Remove any existing PERSONALIZATION_DONE entries
env_lines = [line for line in env_lines if not line.startswith('PERSONALIZATION_DONE=')]
# Add PERSONALIZATION_DONE=False since user skipped
env_lines.append("PERSONALIZATION_DONE=False\n")
# Write back to .env file
with open('.env', 'w') as f:
f.writelines(env_lines)
# Update environment variable
os.environ['PERSONALIZATION_DONE'] = "False"
logger.info("Set PERSONALIZATION_DONE=False in .env and environment")
except Exception as e:
logger.error(f"Failed to set PERSONALIZATION_DONE: {str(e)}")
logger.info("User skipped personalization. Set PERSONALIZATION_DONE=False")
except Exception as e:
logger.error(f"Error updating PERSONALIZATION_DONE on skip: {str(e)}")
st.error("Error updating environment. You may need to configure personalization later.")
# Update the current step to 5 (ALwrity integrations)
st.session_state.current_step = 5
logger.info("Moving to step 5: ALwrity integrations")
st.rerun()
return {"current_step": 4, "changes_made": True}