API Setup Updates and Tweaks

This commit is contained in:
ajaysi
2025-04-17 23:55:20 +05:30
parent fa4097c9ae
commit 6e60a9fd28
6 changed files with 188 additions and 245 deletions

View File

@@ -1,6 +1,7 @@
"""API key manager components package."""
from .ai_research_setup import render_ai_research_setup
from .ai_research import render_ai_research
from .ai_providers import render_ai_providers
from .final_setup import render_final_setup
from .personalization_setup import render_personalization_setup
@@ -10,6 +11,7 @@ from .website_setup import render_website_setup
__all__ = [
'render_ai_research_setup',
'render_ai_research',
'render_ai_providers',
'render_final_setup',
'render_personalization_setup',

View File

@@ -7,6 +7,8 @@ from ..manager import APIKeyManager
from .base import render_navigation_buttons, render_step_indicator, render_tab_style
from ..wizard_state import next_step, update_progress
from datetime import datetime
import os
from dotenv import load_dotenv
def validate_api_key(key: str) -> bool:
"""Validate if an API key is properly formatted."""
@@ -15,10 +17,53 @@ def validate_api_key(key: str) -> bool:
# Basic validation - check if key is not empty and has minimum length
return len(key.strip()) > 0
def save_to_env_file(key_name: str, key_value: str) -> bool:
"""Save API key to .env file."""
try:
env_path = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))), '.env')
# Read existing .env file
env_contents = []
if os.path.exists(env_path):
with open(env_path, 'r') as f:
env_contents = f.readlines()
# Check if key already exists
key_exists = False
for i, line in enumerate(env_contents):
if line.startswith(f"{key_name}="):
env_contents[i] = f"{key_name}={key_value}\n"
key_exists = True
break
# Add new key if it doesn't exist
if not key_exists:
env_contents.append(f"{key_name}={key_value}\n")
# Write back to .env file
with open(env_path, 'w') as f:
f.writelines(env_contents)
# Reload environment variables to ensure consistency
load_dotenv(override=True)
logger.info(f"[save_to_env_file] Successfully saved {key_name} to .env file")
return True
except Exception as e:
logger.error(f"[save_to_env_file] Error saving to .env file: {str(e)}")
return False
def render_ai_providers(api_key_manager: APIKeyManager) -> Dict[str, Any]:
"""Render the AI providers setup step."""
logger.info("[render_ai_providers] Starting AI providers setup")
try:
# Load environment variables
load_dotenv(override=True)
# Get existing API keys from .env
openai_key = os.getenv('OPENAI_API_KEY', '')
gemini_key = os.getenv('GEMINI_API_KEY', '')
# Initialize wizard state if not already initialized
if 'wizard_state' not in st.session_state:
st.session_state.wizard_state = {
@@ -35,10 +80,7 @@ def render_ai_providers(api_key_manager: APIKeyManager) -> Dict[str, Any]:
# Main content
st.markdown("""
<div class='setup-header'>
<h2>🤖 AI Providers Setup</h2>
<p>Configure your AI service providers for content generation</p>
</div>
<div class='setup-header'><h2>🤖 AI LLM Providers Setup</h2></div>
""", unsafe_allow_html=True)
# Create tabs for different AI providers
@@ -51,7 +93,6 @@ def render_ai_providers(api_key_manager: APIKeyManager) -> Dict[str, Any]:
with tabs[0]:
st.markdown("### Primary AI Providers")
st.markdown("Configure the main AI providers for content creation")
# Create a grid layout for AI provider cards
col1, col2 = st.columns(2)
@@ -59,26 +100,19 @@ def render_ai_providers(api_key_manager: APIKeyManager) -> Dict[str, Any]:
with col1:
# OpenAI Card
with st.container():
st.markdown("""
<div class="ai-provider-card">
<div class="ai-provider-header">
<div class="ai-provider-icon">🤖</div>
<div class="ai-provider-title">OpenAI</div>
</div>
<div class="ai-provider-content">
<p>Power your content with GPT-4 and GPT-3.5 models</p>
<div class="ai-provider-input">
""", unsafe_allow_html=True)
openai_key = st.text_input(
openai_input = st.text_input(
"OpenAI API Key",
value=openai_key,
type="password",
key="openai_key",
help="Enter your OpenAI API key"
help="Enter your OpenAI API key",
placeholder="Power your content generation with GPT-4 AI models"
)
if openai_key:
if validate_api_key(openai_key):
st.success("✅ OpenAI API key found in environment")
elif openai_input:
if validate_api_key(openai_input):
st.markdown("""
<div class="ai-provider-status status-valid">
✓ API key configured
@@ -102,32 +136,23 @@ def render_ai_providers(api_key_manager: APIKeyManager) -> Dict[str, Any]:
**Note:** Keep your API key secure and never share it publicly.
""")
st.markdown("</div></div></div>", unsafe_allow_html=True)
with col2:
# Google Card
with st.container():
st.markdown("""
<div class="ai-provider-card">
<div class="ai-provider-header">
<div class="ai-provider-icon">🔍</div>
<div class="ai-provider-title">Google Gemini</div>
</div>
<div class="ai-provider-content">
<p>Leverage Google's powerful Gemini models</p>
<div class="ai-provider-input">
""", unsafe_allow_html=True)
google_key = st.text_input(
"Google API Key",
gemini_input = st.text_input(
"Google Gemini API Key",
value=gemini_key,
type="password",
key="google_key",
help="Enter your Google API key"
help="Enter your Google API key",
placeholder="Power your content generation with Gemini AI models"
)
if google_key:
if validate_api_key(google_key):
if gemini_key:
st.success("✅ Gemini API key found in environment")
elif gemini_input:
if validate_api_key(gemini_input):
st.markdown("""
<div class="ai-provider-status status-valid">
✓ API key configured
@@ -150,8 +175,6 @@ def render_ai_providers(api_key_manager: APIKeyManager) -> Dict[str, Any]:
**Note:** Make sure to enable the Gemini API in your Google Cloud Console.
""")
st.markdown("</div></div></div>", unsafe_allow_html=True)
with tabs[1]:
st.markdown("### Additional AI Providers")
@@ -193,10 +216,10 @@ def render_ai_providers(api_key_manager: APIKeyManager) -> Dict[str, Any]:
st.info("Mistral integration will be available in the next update")
# Track changes and validate keys
if any([openai_key, google_key]):
if any([openai_input, gemini_input]):
changes_made = True
# Check if at least one valid API key is provided
if validate_api_key(openai_key) or validate_api_key(google_key):
if validate_api_key(openai_input) or validate_api_key(gemini_input):
has_valid_key = True
validation_message = "✅ At least one AI provider configured successfully"
else:
@@ -214,20 +237,33 @@ def render_ai_providers(api_key_manager: APIKeyManager) -> Dict[str, Any]:
# Navigation buttons
if render_navigation_buttons(1, 6, changes_made):
if has_valid_key:
# Store the API keys in a separate session state key
st.session_state['api_keys'] = {
'openai': openai_key if validate_api_key(openai_key) else None,
'google': google_key if validate_api_key(google_key) else None
}
# Save API keys to .env file
if validate_api_key(openai_key):
api_key_manager.save_api_key("openai", openai_key)
logger.info("[render_ai_providers] OpenAI API key saved to .env file")
if validate_api_key(openai_input):
if save_to_env_file("OPENAI_API_KEY", openai_input):
logger.info("[render_ai_providers] OpenAI API key saved to .env file")
else:
st.error("Failed to save OpenAI API key to .env file")
return {"current_step": 1, "error": "Failed to save OpenAI API key"}
if validate_api_key(google_key):
api_key_manager.save_api_key("gemini", google_key)
logger.info("[render_ai_providers] Google Gemini API key saved to .env file")
if validate_api_key(gemini_input):
if save_to_env_file("GEMINI_API_KEY", gemini_input):
logger.info("[render_ai_providers] Google Gemini API key saved to .env file")
else:
st.error("Failed to save Gemini API key to .env file")
return {"current_step": 1, "error": "Failed to save Gemini API key"}
# Reload environment variables to ensure consistency
load_dotenv(override=True)
# Get updated API keys from environment
updated_openai_key = os.getenv('OPENAI_API_KEY', '')
updated_gemini_key = os.getenv('GEMINI_API_KEY', '')
# Store the API keys in session state
st.session_state['api_keys'] = {
'openai': updated_openai_key,
'google': updated_gemini_key
}
# Update progress and move to next step
st.session_state['current_step'] = 2 # Set the next step explicitly

View File

@@ -1,114 +0,0 @@
"""AI providers setup component for API key manager."""
from typing import Dict, Any
from loguru import logger
import streamlit as st
import os
import sys
def render_ai_providers_setup(api_key_manager) -> Dict[str, Any]:
"""
Render the AI providers setup component.
Args:
api_key_manager: API key manager instance
Returns:
Dict[str, Any]: Component state
"""
try:
logger.info("[render_ai_providers_setup] Rendering AI providers setup")
# Display section header
st.header("Step 1: Select AI Providers")
st.markdown("""
Configure your AI providers to enable advanced content generation capabilities.
Choose and set up the AI services you want to use.
""")
# Create columns for different providers
col1, col2 = st.columns(2)
with col1:
st.subheader("OpenAI")
st.markdown("""
OpenAI's GPT models provide powerful natural language processing capabilities.
Get your API key from: [OpenAI Dashboard](https://platform.openai.com/account/api-keys)
""")
openai_key = api_key_manager.get_api_key("openai")
openai_input = st.text_input(
"OpenAI API Key",
value=openai_key if openai_key else "",
type="password",
key="openai_key_input"
)
with col2:
st.subheader("Google Gemini")
st.markdown("""
Google's Gemini models offer advanced AI capabilities.
Get your API key from: [Google AI Studio](https://makersuite.google.com/app/apikey)
""")
gemini_key = api_key_manager.get_api_key("gemini")
gemini_input = st.text_input(
"Gemini API Key",
value=gemini_key if gemini_key else "",
type="password",
key="gemini_key_input"
)
# Optional AI Provider
st.subheader("Additional AI Provider (Optional)")
col1, col2 = st.columns(2)
with col1:
st.markdown("""
Mistral AI provides an alternative model for content generation.
Get your API key from: [Mistral Platform](https://console.mistral.ai/api-keys/)
""")
mistral_key = api_key_manager.get_api_key("mistral")
mistral_input = st.text_input(
"Mistral API Key (Optional)",
value=mistral_key if mistral_key else "",
type="password",
key="mistral_key_input"
)
# Add a note about saving
st.info("""
Note: At least one AI provider (OpenAI or Google Gemini) is required.
Click Continue to save your keys and proceed.
""")
# Save keys if they've changed when proceeding to next step
if st.session_state.get('wizard_current_step', 1) > 1:
if openai_input != openai_key:
api_key_manager.save_api_key("openai", openai_input)
logger.info("[render_ai_providers_setup] OpenAI API key saved")
if gemini_input != gemini_key:
api_key_manager.save_api_key("gemini", gemini_input)
logger.info("[render_ai_providers_setup] Gemini API key saved")
if mistral_input != mistral_key:
api_key_manager.save_api_key("mistral", mistral_input)
logger.info("[render_ai_providers_setup] Mistral API key saved")
# Validate that at least one required provider is configured
if not (openai_input or gemini_input):
st.error("Please configure at least one AI provider (OpenAI or Google Gemini) to proceed.")
return {"current_step": 1, "can_proceed": False}
return {"current_step": 1, "can_proceed": bool(openai_input or gemini_input)}
except Exception as e:
error_msg = f"Error in AI providers setup: {str(e)}"
logger.error(f"[render_ai_providers_setup] {error_msg}")
st.error(error_msg)
return {"current_step": 1, "error": error_msg}

View File

@@ -29,10 +29,7 @@ def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
logger.info("[render_ai_research_setup] Rendering AI research setup component")
st.markdown("""
<div class='setup-header'>
<h2>🔍 AI Research Setup</h2>
<p>Configure your AI research providers for content analysis and research</p>
</div>
<div class='setup-header'><h2>🔍 AI Web Research API Setup</h2></div>
""", unsafe_allow_html=True)
# Create two columns for different search types
@@ -188,19 +185,7 @@ def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
st.markdown("</div></div>", unsafe_allow_html=True)
# Disabled Options Expander
with st.expander("🔜 Coming Soon - More Search Options", expanded=False):
st.markdown("""
<div style='opacity: 0.7;'>
<h4>Bing Search API</h4>
<p>Microsoft's powerful search API with web, news, and image search capabilities.</p>
<h4>Google Search API</h4>
<p>Google's programmable search engine with customizable search parameters.</p>
<p><em>These integrations are under development and will be available soon!</em></p>
</div>
""", unsafe_allow_html=True)
# Track changes
changes_made = bool(serpapi_key or tavily_key or metaphor_key or firecrawl_key)
@@ -246,56 +231,97 @@ def render_ai_research_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
st.error("Please configure at least one research provider to continue")
# Detailed Information Section
st.markdown("""
---
### Understanding Your Research Options
st.markdown("---")
st.markdown("### Understanding Your Research Options")
#### The Usual: Traditional Search
**SerpAPI**
- Real-time search results from multiple search engines
- Access to structured data from search results
- Great for gathering general information and market research
- Includes features like:
- Web search results
- News articles
- Knowledge graphs
- Related questions
# Create four columns for the information popovers
info_col1, info_col2, info_col3, info_col4 = st.columns(4)
#### AI Deep Research: Advanced Search Capabilities
# The Usual: Traditional Search Popover
with info_col1:
with st.popover("#### The Usual: Traditional Search"):
st.markdown("""
**SerpAPI**
- Real-time search results from multiple search engines
- Access to structured data from search results
- Great for gathering general information and market research
- Includes features like:
- Web search results
- News articles
- Knowledge graphs
- Related questions
""")
**Tavily AI**
- AI-powered search with semantic understanding
- Automatically summarizes and analyzes search results
- Perfect for:
- Deep research tasks
- Academic research
- Fact-checking
- Real-time information gathering
# AI Deep Research Popover
with info_col2:
with st.popover("#### AI Deep Research: Advanced Search Capabilities"):
st.markdown("""
**Tavily AI**
- AI-powered search with semantic understanding
- Automatically summarizes and analyzes search results
- Perfect for:
- Deep research tasks
- Academic research
- Fact-checking
- Real-time information gathering
**Metaphor/Exa**
- Neural search engine that understands context and meaning
- Specialized in finding highly relevant content
- Ideal for:
- Technical research
- Finding similar content
- Discovering patterns in research
- Understanding topic landscapes
""")
**Metaphor/Exa**
- Neural search engine that understands context and meaning
- Specialized in finding highly relevant content
- Ideal for:
- Technical research
- Finding similar content
- Discovering patterns in research
- Understanding topic landscapes
# Choosing the Right Tool Popover
with info_col3:
with st.popover("#### Choosing the Right Tool"):
st.markdown("""
1. **For General Research:**
- Start with SerpAPI for broad coverage and structured data
2. **For Deep Analysis:**
- Use Tavily AI when you need AI-powered insights
- Choose Metaphor/Exa for neural search and pattern discovery
3. **For Comprehensive Research:**
- Combine multiple tools to get the most complete picture
- Use SerpAPI for initial research
- Follow up with AI tools for deeper insights
> **Pro Tip:** Configure multiple providers to ensure you have backup options and can cross-reference results for better accuracy.
""")
#### Choosing the Right Tool
1. **For General Research:**
- Start with SerpAPI for broad coverage and structured data
2. **For Deep Analysis:**
- Use Tavily AI when you need AI-powered insights
- Choose Metaphor/Exa for neural search and pattern discovery
3. **For Comprehensive Research:**
- Combine multiple tools to get the most complete picture
- Use SerpAPI for initial research
- Follow up with AI tools for deeper insights
> **Pro Tip:** Configure multiple providers to ensure you have backup options and can cross-reference results for better accuracy.
""")
# Coming Soon Popover
with info_col4:
with st.popover("#### 🔜 Coming Soon - More Search Options"):
st.markdown("""
**Bing Search API**
- Microsoft's powerful search API with comprehensive capabilities
- Features include:
- Web search with advanced filtering
- News articles with sentiment analysis
- Image search with visual recognition
- Video search with content understanding
- Custom search parameters for targeted results
**Google Search API**
- Google's programmable search engine with extensive features
- Capabilities include:
- Custom search engine creation
- Site-specific search
- Image and video search
- News search with time-based filtering
- Knowledge graph integration
**Additional Planned Integrations:**
- **DuckDuckGo API**: Privacy-focused search with no tracking
- **Brave Search API**: Independent search engine with unique features
- **Perplexity API**: AI-powered research assistant with real-time data
> **Note:** These integrations are under active development and will be available in future updates.
""")
return {"current_step": 3, "changes_made": changes_made}

View File

@@ -4,12 +4,6 @@ import streamlit as st
from typing import Dict, Any
from loguru import logger
from ..styles import API_KEY_MANAGER_STYLES
from ..wizard_state import (
get_current_step,
next_step,
previous_step,
can_proceed_to_next_step
)
def render_step_indicator(current_step: int, total_steps: int) -> None:
"""Render the step indicator."""

View File

@@ -36,19 +36,20 @@ def render_website_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
"""
logger.info("[render_website_setup] Rendering website setup component")
st.markdown("### Step 2: Website Setup")
st.markdown("### Step 2: Enter Your Website URL for Analysis (Optional)")
# Create two columns for input and results
col1, col2 = st.columns([1, 1])
with col1:
st.markdown("#### Enter Website URL")
url = st.text_input("Website URL", placeholder="https://example.com")
logger.debug(f"[render_website_setup] URL input value: {url}")
url = st.text_input("Enter your website URL, if you own one", placeholder="https://example.com")
logger.info(f"[render_website_setup] URL input value: {url}")
analyze_type = st.radio(
"Analysis Type",
["Basic Analysis", "Full Analysis with SEO"],
["Basic Website Analysis", "Full Website Analysis with SEO"],
horizontal=True,
label_visibility="hidden",
help="Choose between basic website analysis or comprehensive SEO analysis"
)
@@ -115,8 +116,6 @@ def render_website_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
st.warning("Please enter a valid URL")
with col2:
st.markdown("#### Analysis Results")
# Check if we have analysis results
if 'website_analysis' in st.session_state:
results = st.session_state.website_analysis
@@ -126,7 +125,7 @@ def render_website_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
analysis = data.get('analysis', {})
# Create tabs for different sections
if analyze_type == "Full Analysis with SEO":
if analyze_type == "Full Website Analysis with SEO":
tab1, tab2, tab3, tab4, tab5 = st.tabs([
"Basic Metrics",
"Content Analysis",
@@ -237,7 +236,7 @@ def render_website_setup(api_key_manager: APIKeyManager) -> Dict[str, Any]:
for issue in issues:
st.write(f"{issue}")
with tab4 if analyze_type == "Basic Analysis" else tab5:
with tab4 if analyze_type == "Basic Website Analysis" else tab5:
st.markdown("##### Strategy Recommendations")
strategy_info = analysis.get('strategy', {})