Fix environment variable handling in setup: PERSONALIZATION_DONE and FINAL_SETUP_COMPLETE
This commit is contained in:
@@ -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}
|
||||
Reference in New Issue
Block a user