"""Personalization setup component for the API key manager."""
import streamlit as st
from loguru import logger
import sys
import json
from typing import Dict, Any
from ..manager import APIKeyManager
from ....web_crawlers.async_web_crawler import AsyncWebCrawlerService
from ....personalization.style_analyzer import StyleAnalyzer
from pages.style_utils import (
get_analysis_section,
get_glass_container,
get_info_section,
get_example_box
)
from .base import render_navigation_buttons
from .alwrity_integrations import render_alwrity_integrations
import asyncio
import os
from pathlib import Path
import yaml
# Configure logger to output to both file and stdout
logger.remove() # Remove default handler
logger.add(
"logs/personalization_setup.log",
rotation="500 MB",
retention="10 days",
level="DEBUG",
format="{time:YYYY-MM-DD HH:mm:ss} | {level} | {message}"
)
logger.add(
sys.stdout,
level="INFO",
format="{time:YYYY-MM-DD HH:mm:ss} | {level: <8} | {message}"
)
def load_main_config() -> Dict[str, Any]:
"""Load the main configuration file."""
config_path = os.path.join("lib", "workspace", "alwrity_config", "main_config.json")
try:
with open(config_path, 'r') as f:
return json.load(f)
except Exception as e:
logger.error(f"Error loading main_config.json: {str(e)}")
return {}
def save_main_config(config: Dict[str, Any]) -> bool:
"""Save the main configuration file."""
try:
config_path = os.path.join("lib", "workspace", "alwrity_config", "main_config.json")
os.makedirs(os.path.dirname(config_path), exist_ok=True)
with open(config_path, 'w') as f:
json.dump(config, f, indent=4)
return True
except Exception as e:
logger.error(f"Error saving main_config.json: {str(e)}")
return False
def display_style_analysis(analysis_results: dict):
"""Display the style analysis results in a structured format."""
try:
# Writing Style Section
writing_style = analysis_results.get("writing_style", {})
writing_style_content = f"""
""", 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("""
""", unsafe_allow_html=True)
# Blog Content Characteristics
st.markdown("#### Blog Content Characteristics")
blog_settings = main_config.get("Blog Content Characteristics", {})
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("
", unsafe_allow_html=True)
with info_col:
st.markdown("""
""", unsafe_allow_html=True)
st.markdown("""
### 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
- Impacts SEO performance
**Number of Results**
- More results = better analysis
- Consider processing time
- Balance quality vs. speed
**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
""", unsafe_allow_html=True)
st.markdown("
", unsafe_allow_html=True)
# Close the container
st.markdown("
", unsafe_allow_html=True)
# Add some spacing before the save button
st.markdown("