Spaces:
Runtime error
Runtime error
| import streamlit as st | |
| import base64 | |
| from io import BytesIO | |
| import json | |
| import time | |
| import os | |
| from utils import create_slide_preview, TEMPLATES, generate_slide_content | |
| from enhanced_pptx import enhanced_create_ppt | |
| from slide_editor_enhancements import render_enhanced_slide_editor | |
| from multi_llm_provider import get_ai_manager | |
| from visual_elements import search_stock_images, download_image, analyze_slide_for_visuals | |
| # Check for API keys | |
| api_key = os.getenv("ANTHROPIC_API_KEY") | |
| openai_key = os.getenv("OPENAI_API_KEY") | |
| deepseek_key = os.getenv("DEEPSEEK_API_KEY") | |
| perplexity_key = os.getenv("PERPLEXITY_API_KEY") | |
| pexels_key = os.getenv("PEXELS_API_KEY") | |
| def nav_button(label, stage, icon=None, primary=False): | |
| """Create a navigation button with improved styling""" | |
| button_style = "primary" if primary else "secondary" | |
| icon_text = f"{icon} " if icon else "" | |
| if st.button(f"{icon_text}{label}", key=f"nav_{stage}", type=button_style, use_container_width=True): | |
| st.session_state.current_stage = stage | |
| st.rerun() | |
| def display_navigation_bar(): | |
| """Display navigation bar at the top of the page""" | |
| stages = [ | |
| {"name": "ideation", "label": "Ideation", "icon": "π‘"}, | |
| {"name": "storyboard", "label": "Storyboard", "icon": "π"}, | |
| {"name": "template", "label": "Template", "icon": "π¨"}, | |
| {"name": "slides", "label": "Edit Slides", "icon": "πΌοΈ"}, | |
| {"name": "export", "label": "Export", "icon": "π€"} | |
| ] | |
| cols = st.columns(len(stages)) | |
| for i, stage in enumerate(stages): | |
| with cols[i]: | |
| is_current = st.session_state.current_stage == stage["name"] | |
| # Create a clickable button with custom CSS | |
| if st.button( | |
| f"{stage['icon']} {stage['label']}", | |
| key=f"nav_top_{stage['name']}", | |
| disabled=is_current, | |
| use_container_width=True, | |
| type="primary" if is_current else "secondary" | |
| ): | |
| # If we've already completed previous stages, allow direct navigation | |
| if stage["name"] in ["ideation"] or ( | |
| stage["name"] == "storyboard" and st.session_state.storyboard | |
| ) or ( | |
| stage["name"] == "template" and st.session_state.storyboard | |
| ) or ( | |
| stage["name"] == "slides" and st.session_state.slides_content | |
| ) or ( | |
| stage["name"] == "export" and st.session_state.slides_content | |
| ): | |
| st.session_state.current_stage = stage["name"] | |
| st.rerun() | |
| else: | |
| st.warning(f"Please complete the previous stages before going to {stage['label']}") | |
| # Progress bar | |
| stages_order = ["ideation", "storyboard", "template", "slides", "export"] | |
| current_idx = stages_order.index(st.session_state.current_stage) | |
| progress = current_idx / (len(stages_order) - 1) | |
| st.progress(progress) | |
| def render_ai_settings(): | |
| """Render AI settings sidebar section""" | |
| st.sidebar.write("## π§ AI Settings") | |
| # Get AI manager | |
| ai_manager = get_ai_manager() | |
| available_models = ai_manager.get_available_models() | |
| if not available_models: | |
| st.sidebar.warning("No AI providers configured. Add API keys in secrets.") | |
| default_model = "claude-3-sonnet-20250219" | |
| else: | |
| default_model = list(available_models.keys())[0] if available_models else "claude-3-sonnet-20250219" | |
| # Select default model for the whole presentation | |
| selected_model = st.sidebar.selectbox( | |
| "Default AI Model", | |
| options=list(available_models.keys()), | |
| format_func=lambda x: available_models.get(x, x), | |
| index=0 if default_model in available_models else 0 | |
| ) | |
| st.session_state.default_model = selected_model | |
| # Temperature setting | |
| temperature = st.sidebar.slider( | |
| "AI Creativity", | |
| min_value=0.0, | |
| max_value=1.0, | |
| value=0.7, | |
| step=0.1, | |
| help="Higher values make output more creative but less predictable" | |
| ) | |
| st.session_state.ai_temperature = temperature | |
| # Web search integration | |
| enable_search = st.sidebar.checkbox( | |
| "Enable Web Search", | |
| value=st.session_state.get("enable_web_search", False), | |
| help="Use Perplexity to search for up-to-date information", | |
| disabled=not perplexity_key | |
| ) | |
| st.session_state.enable_web_search = enable_search | |
| if enable_search and not perplexity_key: | |
| st.sidebar.warning("Perplexity API key required for web search") | |
| # Stock image settings | |
| st.sidebar.write("## πΌοΈ Image Settings") | |
| if not pexels_key: | |
| st.sidebar.warning("Pexels API key required for better stock images") | |
| # Test different AI providers | |
| if st.sidebar.button("Test AI Providers"): | |
| with st.sidebar: | |
| st.write("Testing AI providers...") | |
| for model in list(available_models.keys())[:2]: # Test first two models | |
| try: | |
| with st.spinner(f"Testing {model}..."): | |
| response = ai_manager.generate_text( | |
| "Write a one-sentence test response.", | |
| model=model, | |
| max_tokens=50 | |
| ) | |
| st.success(f"{model}: {response}") | |
| except Exception as e: | |
| st.error(f"{model}: Error - {str(e)}") | |
| def render_ideation_stage(): | |
| """Render the ideation stage UI""" | |
| display_navigation_bar() | |
| # Add AI settings sidebar | |
| render_ai_settings() | |
| st.header("π‘ Step 1: Presentation Ideation") | |
| st.write("Let's start by defining the purpose and scope of your presentation.") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.session_state.presentation_title = st.text_input( | |
| "Presentation Title", | |
| value=st.session_state.presentation_title | |
| ) | |
| st.session_state.presentation_purpose = st.text_area( | |
| "What's the purpose of this presentation?", | |
| value=st.session_state.presentation_purpose, | |
| help="E.g., Inform, persuade, pitch a product, update stakeholders, etc." | |
| ) | |
| with col2: | |
| st.session_state.target_audience = st.text_area( | |
| "Who is your target audience?", | |
| value=st.session_state.target_audience, | |
| help="E.g., Executives, customers, technical team, general public, etc." | |
| ) | |
| # Add example suggestions | |
| st.write("π **Example presentations:**") | |
| examples = [ | |
| "Quarterly Business Review", | |
| "Product Launch Presentation", | |
| "Team Project Update", | |
| "Investor Pitch Deck" | |
| ] | |
| # Create two columns for examples | |
| ex_col1, ex_col2 = st.columns(2) | |
| for i, example in enumerate(examples): | |
| with ex_col1 if i % 2 == 0 else ex_col2: | |
| if st.button(f"π {example}", key=f"example_{example}"): | |
| st.session_state.presentation_title = example | |
| # Set appropriate purpose and audience based on example | |
| if "Quarterly" in example: | |
| st.session_state.presentation_purpose = "Review business performance for the past quarter and outline goals for the next quarter" | |
| st.session_state.target_audience = "Executives and department heads" | |
| elif "Product" in example: | |
| st.session_state.presentation_purpose = "Introduce a new product to customers and highlight its key features and benefits" | |
| st.session_state.target_audience = "Potential customers and sales team" | |
| elif "Project" in example: | |
| st.session_state.presentation_purpose = "Update team members on project progress, achievements, and next steps" | |
| st.session_state.target_audience = "Project stakeholders and team members" | |
| elif "Investor" in example: | |
| st.session_state.presentation_purpose = "Pitch our business to potential investors to secure funding" | |
| st.session_state.target_audience = "Venture capitalists and angel investors" | |
| st.rerun() | |
| # AI model selection for storyboard generation | |
| st.write("### π§ AI Engine Selection") | |
| # Get AI manager | |
| ai_manager = get_ai_manager() | |
| available_models = ai_manager.get_available_models() | |
| cols = st.columns([2, 1]) | |
| with cols[0]: | |
| selected_model = st.selectbox( | |
| "AI Model for Storyboard Generation", | |
| options=list(available_models.keys()), | |
| format_func=lambda x: available_models.get(x, x), | |
| index=0, | |
| key="storyboard_model" | |
| ) | |
| with cols[1]: | |
| web_research = st.checkbox( | |
| "Include Web Research", | |
| value=st.session_state.get("enable_web_search", False), | |
| disabled=not perplexity_key, | |
| help="Search the web for the latest information related to your presentation topic" | |
| ) | |
| # Generate button with loading indicator | |
| st.markdown("---") | |
| if st.button("π Generate Storyboard", type="primary", use_container_width=True): | |
| if not st.session_state.presentation_title or not st.session_state.presentation_purpose: | |
| st.warning("Please provide at least a title and purpose to proceed.") | |
| else: | |
| with st.spinner("π§ SlideGator.AI is chomping on your presentation ideas..."): | |
| from utils import generate_storyboard | |
| # If web research is enabled, perform a search first | |
| if web_research and perplexity_key: | |
| with st.spinner("π Researching the latest information..."): | |
| search_query = f"latest information about {st.session_state.presentation_title}" | |
| search_results = ai_manager.web_search(search_query) | |
| if search_results: | |
| # Create a research summary | |
| st.success(f"Found {len(search_results)} relevant sources of information!") | |
| # Store in session state | |
| st.session_state.web_research = search_results | |
| else: | |
| st.warning("No research results found. Proceeding without research.") | |
| # Generate storyboard with the selected model | |
| storyboard = generate_storyboard( | |
| st.session_state.presentation_title, | |
| st.session_state.presentation_purpose, | |
| st.session_state.target_audience, | |
| model=selected_model | |
| ) | |
| if storyboard: | |
| st.session_state.storyboard = storyboard | |
| st.session_state.current_stage = "storyboard" | |
| st.success("Storyboard created successfully!") | |
| st.rerun() | |
| def render_storyboard_stage(): | |
| """Render the storyboard review stage UI""" | |
| display_navigation_bar() | |
| st.header("π Step 2: Review and Edit Storyboard") | |
| st.write(f"Storyboard for: **{st.session_state.presentation_title}**") | |
| st.write("Expand each slide to edit its content or add notes.") | |
| # Display storyboard for review with edit options | |
| edited_storyboard = [] | |
| # Add a "regenerate" button and AI options | |
| col1, col2, col3 = st.columns([2, 1, 1]) | |
| with col1: | |
| # Get AI manager | |
| ai_manager = get_ai_manager() | |
| available_models = ai_manager.get_available_models() | |
| selected_model = st.selectbox( | |
| "AI Model", | |
| options=list(available_models.keys()), | |
| format_func=lambda x: available_models.get(x, x), | |
| index=0, | |
| key="storyboard_regen_model" | |
| ) | |
| with col2: | |
| if st.button("π Regenerate All", help="Create a new storyboard with current title/purpose"): | |
| from utils import generate_storyboard | |
| with st.spinner("π SlideGator.AI is rethinking your presentation structure..."): | |
| storyboard = generate_storyboard( | |
| st.session_state.presentation_title, | |
| st.session_state.presentation_purpose, | |
| st.session_state.target_audience, | |
| model=selected_model | |
| ) | |
| if storyboard: | |
| st.session_state.storyboard = storyboard | |
| st.success("Storyboard regenerated!") | |
| st.rerun() | |
| with col3: | |
| if st.button("π Analyze Flow", help="Analyze the narrative flow of your presentation"): | |
| with st.spinner("π§ Analyzing presentation flow..."): | |
| # Convert storyboard to text for analysis | |
| storyboard_text = "" | |
| for i, slide in enumerate(st.session_state.storyboard): | |
| storyboard_text += f"Slide {i+1}: {slide.get('title', 'Untitled')}\n" | |
| storyboard_text += f"Purpose: {slide.get('purpose', '')}\n" | |
| key_points = slide.get('key_points', []) | |
| if isinstance(key_points, list): | |
| for point in key_points: | |
| storyboard_text += f"- {point}\n" | |
| else: | |
| storyboard_text += f"- {key_points}\n" | |
| storyboard_text += "\n" | |
| # Analyze the flow | |
| prompt = f""" | |
| You are an expert presentation designer. | |
| Please analyze the flow and structure of this presentation storyboard: | |
| {storyboard_text} | |
| Provide feedback on: | |
| 1. The narrative flow and logical progression | |
| 2. Any gaps in the content | |
| 3. Balance of information across slides | |
| 4. Suggestions for improvement | |
| Be constructive and specific. | |
| """ | |
| try: | |
| analysis = ai_manager.generate_text( | |
| prompt=prompt, | |
| model=selected_model, | |
| system_prompt="You are an expert presentation flow analyst focusing on business presentations.", | |
| temperature=0.3, | |
| max_tokens=1000 | |
| ) | |
| # Display analysis | |
| st.info("### Presentation Flow Analysis") | |
| st.write(analysis) | |
| except Exception as e: | |
| st.error(f"Error analyzing presentation flow: {str(e)}") | |
| # Add slide button with options | |
| col1, col2 = st.columns([3, 1]) | |
| with col1: | |
| slide_position = st.radio( | |
| "Add new slide:", | |
| ["At End", "After Current", "Before Current"], | |
| horizontal=True | |
| ) | |
| with col2: | |
| if st.button("β Add New Slide", use_container_width=True): | |
| # Create a new slide | |
| new_slide = { | |
| 'title': 'New Slide', | |
| 'purpose': 'Additional content', | |
| 'key_points': ['Add your content here'], | |
| 'visual_elements': ['Suggested visuals will appear here'] | |
| } | |
| # Insert at the selected position | |
| if slide_position == "At End": | |
| st.session_state.storyboard.append(new_slide) | |
| elif slide_position == "After Current": | |
| # Get current slide index from session state or default to last | |
| current_idx = st.session_state.get("current_storyboard_slide", len(st.session_state.storyboard) - 1) | |
| st.session_state.storyboard.insert(current_idx + 1, new_slide) | |
| else: # Before Current | |
| current_idx = st.session_state.get("current_storyboard_slide", 0) | |
| st.session_state.storyboard.insert(max(0, current_idx), new_slide) | |
| st.rerun() | |
| # Add slide templates section | |
| with st.expander("π Slide Templates"): | |
| st.write("Add pre-designed slide templates to your presentation:") | |
| template_cols = st.columns(3) | |
| slide_templates = [ | |
| {"name": "Section Divider", "icon": "π·οΈ", "title": "Section Title", | |
| "purpose": "Introduce a new section", | |
| "key_points": ["A clean slide to mark a new section of your presentation"]}, | |
| {"name": "Comparison", "icon": "βοΈ", "title": "Comparison", | |
| "purpose": "Compare two options or approaches", | |
| "key_points": ["Option A benefits", "Option A challenges", "Option B benefits", "Option B challenges"], | |
| "visual_elements": ["Two-column layout", "Comparison table or chart"]}, | |
| {"name": "Quote", "icon": "π¬", "title": "Key Quote", | |
| "purpose": "Highlight an important quote", | |
| "key_points": ["The quote goes here", "- Attribution"], | |
| "visual_elements": ["Quotation marks graphic", "Simple background"]}, | |
| {"name": "Data Visualization", "icon": "π", "title": "Key Metrics", | |
| "purpose": "Present important data", | |
| "key_points": ["Metric 1 and its significance", "Metric 2 and its significance", "Trends and patterns"], | |
| "visual_elements": ["Chart or graph", "Data visualization"]}, | |
| {"name": "Call to Action", "icon": "π―", "title": "Next Steps", | |
| "purpose": "Define clear action items", | |
| "key_points": ["Specific action item 1", "Specific action item 2", "Timeline and ownership"], | |
| "visual_elements": ["Arrow or path graphic", "Timeline visualization"]}, | |
| {"name": "Team Slide", "icon": "π₯", "title": "Our Team", | |
| "purpose": "Introduce key team members", | |
| "key_points": ["Team member 1 with role", "Team member 2 with role", "Team member 3 with role"], | |
| "visual_elements": ["Team photos or icons", "Organizational chart"]} | |
| ] | |
| for i, template in enumerate(slide_templates): | |
| with template_cols[i % 3]: | |
| if st.button(f"{template['icon']} {template['name']}", key=f"template_{template['name']}"): | |
| # Create a new slide based on the template | |
| new_slide = { | |
| 'title': template['title'], | |
| 'purpose': template['purpose'], | |
| 'key_points': template['key_points'], | |
| 'visual_elements': template.get('visual_elements', []) | |
| } | |
| # Add to storyboard | |
| st.session_state.storyboard.append(new_slide) | |
| st.success(f"Added {template['name']} slide!") | |
| st.rerun() | |
| # Display storyboard slides | |
| for i, slide in enumerate(st.session_state.storyboard): | |
| # Set current slide in session state when expander is opened | |
| is_expanded = i == 0 or st.session_state.get("current_storyboard_slide") == i | |
| with st.expander(f"Slide {i+1}: {slide.get('title', 'Untitled')}", expanded=is_expanded): | |
| if is_expanded: | |
| st.session_state.current_storyboard_slide = i | |
| # Main slide content | |
| cols = st.columns([3, 1]) | |
| with cols[0]: | |
| slide_title = st.text_input(f"Title ###{i}", value=slide.get('title', 'Untitled')) | |
| with cols[1]: | |
| # Slide reordering and deletion | |
| cols2 = st.columns([1, 1, 1]) | |
| with cols2[0]: | |
| if i > 0 and st.button("β¬οΈ", key=f"up_{i}"): | |
| st.session_state.storyboard[i], st.session_state.storyboard[i-1] = st.session_state.storyboard[i-1], st.session_state.storyboard[i] | |
| st.session_state.current_storyboard_slide = i - 1 | |
| st.rerun() | |
| with cols2[1]: | |
| if i < len(st.session_state.storyboard) - 1 and st.button("β¬οΈ", key=f"down_{i}"): | |
| st.session_state.storyboard[i], st.session_state.storyboard[i+1] = st.session_state.storyboard[i+1], st.session_state.storyboard[i] | |
| st.session_state.current_storyboard_slide = i + 1 | |
| st.rerun() | |
| with cols2[2]: | |
| if st.button("ποΈ", key=f"delete_{i}"): | |
| if len(st.session_state.storyboard) > 1: # Prevent deleting the last slide | |
| st.session_state.storyboard.pop(i) | |
| st.session_state.current_storyboard_slide = min(i, len(st.session_state.storyboard) - 1) | |
| st.rerun() | |
| else: | |
| st.error("Cannot delete the last slide") | |
| slide_purpose = st.text_area(f"Purpose ###{i}", value=slide.get('purpose', '')) | |
| # Handle key points (could be string or list) | |
| if isinstance(slide.get('key_points', ""), list): | |
| key_points_text = "\n".join(slide['key_points']) | |
| else: | |
| key_points_text = slide.get('key_points', "") | |
| key_points = st.text_area(f"Key Points (one per line) ###{i}", value=key_points_text) | |
| # Handle visual elements (could be string or list) | |
| if isinstance(slide.get('visual_elements', ""), list): | |
| visual_elements_text = "\n".join(slide['visual_elements']) | |
| else: | |
| visual_elements_text = slide.get('visual_elements', "") | |
| visual_elements = st.text_area(f"Visual Elements (one per line) ###{i}", value=visual_elements_text) | |
| # AI enhancement options | |
| with st.expander("π§ AI Enhancement"): | |
| ai_cols = st.columns(2) | |
| with ai_cols[0]: | |
| # Get AI manager | |
| ai_manager = get_ai_manager() | |
| available_models = ai_manager.get_available_models() | |
| enhancement_model = st.selectbox( | |
| "AI Model", | |
| options=list(available_models.keys()), | |
| format_func=lambda x: available_models.get(x, x), | |
| index=0, | |
| key=f"enhance_model_{i}" | |
| ) | |
| with ai_cols[1]: | |
| enhancement_type = st.selectbox( | |
| "Enhancement Type", | |
| ["Content", "Title", "Visual Suggestions", "All"], | |
| key=f"enhance_type_{i}" | |
| ) | |
| if st.button("β¨ Enhance with AI", key=f"enhance_slide_{i}"): | |
| with st.spinner("π§ Enhancing slide content..."): | |
| # Update slide with current edits first | |
| updated_slide = { | |
| 'title': slide_title, | |
| 'purpose': slide_purpose, | |
| 'key_points': key_points.split("\n") if "\n" in key_points else [key_points] if key_points else [], | |
| 'visual_elements': visual_elements.split("\n") if "\n" in visual_elements else [visual_elements] if visual_elements else [] | |
| } | |
| try: | |
| # Create appropriate prompt based on enhancement type | |
| if enhancement_type == "Content" or enhancement_type == "All": | |
| content_prompt = f""" | |
| You are an expert presentation content creator. | |
| Enhance the content for this slide: | |
| Title: {updated_slide['title']} | |
| Purpose: {updated_slide['purpose']} | |
| Current content: {updated_slide['key_points']} | |
| Make the content more impactful, clear, and aligned with the slide's purpose. | |
| Return only the enhanced content points as a JSON array of strings like this: | |
| ["Enhanced point 1", "Enhanced point 2", "Enhanced point 3"] | |
| """ | |
| content_response = ai_manager.generate_text( | |
| prompt=content_prompt, | |
| model=enhancement_model, | |
| system_prompt="You are an expert presentation content creator. Return only JSON array of enhanced bullet points.", | |
| temperature=0.7, | |
| max_tokens=500 | |
| ) | |
| # Extract JSON array from response | |
| try: | |
| json_start = content_response.find("[") | |
| json_end = content_response.rfind("]") + 1 | |
| if json_start >= 0 and json_end > 0: | |
| json_str = content_response[json_start:json_end] | |
| enhanced_content = json.loads(json_str) | |
| updated_slide['key_points'] = enhanced_content | |
| except Exception as e: | |
| st.error(f"Error parsing content enhancement: {str(e)}") | |
| if enhancement_type == "Title" or enhancement_type == "All": | |
| title_prompt = f""" | |
| You are an expert presentation title creator. | |
| Current slide title: {updated_slide['title']} | |
| Slide purpose: {updated_slide['purpose']} | |
| Slide content: {updated_slide['key_points']} | |
| Create a more engaging, clear, and impactful title for this slide. | |
| Return only the new title with no additional text or explanation. | |
| """ | |
| title_response = ai_manager.generate_text( | |
| prompt=title_prompt, | |
| model=enhancement_model, | |
| system_prompt="You are an expert presentation title creator. Return only the enhanced title.", | |
| temperature=0.7, | |
| max_tokens=50 | |
| ) | |
| updated_slide['title'] = title_response.strip() | |
| if enhancement_type == "Visual Suggestions" or enhancement_type == "All": | |
| visual_prompt = f""" | |
| You are an expert presentation visual designer. | |
| Slide title: {updated_slide['title']} | |
| Slide purpose: {updated_slide['purpose']} | |
| Slide content: {updated_slide['key_points']} | |
| Suggest specific visual elements that would enhance this slide. | |
| Consider charts, diagrams, images, icons, and layout suggestions. | |
| Return only a JSON array of specific recommendations like: | |
| ["Bar chart comparing quarterly revenue", "Icon representing customer satisfaction", "Split-screen layout with image on left"] | |
| """ | |
| visual_response = ai_manager.generate_text( | |
| prompt=visual_prompt, | |
| model=enhancement_model, | |
| system_prompt="You are an expert presentation visual designer. Return only a JSON array of visual element recommendations.", | |
| temperature=0.7, | |
| max_tokens=300 | |
| ) | |
| # Extract JSON array from response | |
| try: | |
| json_start = visual_response.find("[") | |
| json_end = visual_response.rfind("]") + 1 | |
| if json_start >= 0 and json_end > 0: | |
| json_str = visual_response[json_start:json_end] | |
| enhanced_visuals = json.loads(json_str) | |
| updated_slide['visual_elements'] = enhanced_visuals | |
| except Exception as e: | |
| st.error(f"Error parsing visual enhancement: {str(e)}") | |
| # Update the storyboard with enhanced slide | |
| st.session_state.storyboard[i] = updated_slide | |
| st.success("Slide enhanced with AI!") | |
| st.rerun() | |
| except Exception as e: | |
| st.error(f"Error enhancing slide: {str(e)}") | |
| # Web search enhancement option | |
| if perplexity_key: | |
| with st.expander("π Enhance with Web Search"): | |
| search_query = st.text_input( | |
| "Search Query", | |
| value=f"latest information about {slide_title}", | |
| key=f"search_query_{i}" | |
| ) | |
| if st.button("π Search & Enhance", key=f"search_enhance_{i}"): | |
| # Update slide with current edits first | |
| updated_slide = { | |
| 'title': slide_title, | |
| 'purpose': slide_purpose, | |
| 'key_points': key_points.split("\n") if "\n" in key_points else [key_points] if key_points else [], | |
| 'visual_elements': visual_elements.split("\n") if "\n" in visual_elements else [visual_elements] if visual_elements else [] | |
| } | |
| # Enhance with web search | |
| enhanced_slide = ai_manager.enhance_with_web_search(updated_slide, search_query) | |
| # Update the storyboard | |
| st.session_state.storyboard[i] = enhanced_slide | |
| st.success("Slide enhanced with web search results!") | |
| st.rerun() | |
| # Update storyboard with edits | |
| edited_slide = { | |
| 'title': slide_title, | |
| 'purpose': slide_purpose, | |
| 'key_points': key_points.split("\n") if "\n" in key_points else [key_points] if key_points else [], | |
| 'visual_elements': visual_elements.split("\n") if "\n" in visual_elements else [visual_elements] if visual_elements else [] | |
| } | |
| edited_storyboard.append(edited_slide) | |
| # Update the storyboard in session state | |
| st.session_state.storyboard = edited_storyboard | |
| st.markdown("---") | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| nav_button("Back to Ideation", "ideation", icon="β¬ οΈ") | |
| with col2: | |
| nav_button("Continue to Template Selection", "template", icon="β‘οΈ", primary=True) |