""" UI components for the Magic Story Creator application """ import gradio as gr from config import constants def create_header(): """Create the main header section of the application""" return gr.HTML( '
' '

Magic Story Creator

' 'Magic Wand' "
" ) def create_instructions_accordion(): """Create the instructions accordion""" with gr.Accordion( "How to Create Your Magical Story", elem_classes="gr-accordion", open=False ) as accordion: gr.HTML("""
Magic Wand

Welcome to Magic Story Creator!

This magical tool helps you create personalized stories for children. Follow these simple steps:

Step 1: Choose Your Adventure

Select a story type and tone that your child will enjoy.

Example: Fantasy with Enthusiastic tone

Step 2: Child's Details

Tell us about the child who will be enjoying the story.

Example: Age 6, English language, interests in dinosaurs and space

Step 3: Story Details

Add a subject for your story and how long you'd like it to be.

Example: "Quantum Computing" for 3 minutes of reading time

Step 4: Create Magic!

Click "Create My Magical Story" and watch the magic happen! Once your story appears, click "Create Illustrated Chapters" to add pictures.

""") return accordion def create_story_tab_header(): """Create the header for the story tab""" return gr.HTML("""
Magic Wand
Let's create a magical story just for you!
""") def create_step_heading(number, title): """Create a step heading""" return gr.HTML(f"""
Step {number}: {title}
""") def create_story_options(): """Create story type and tone selection options""" with gr.Row(): # Story Type with gr.Column(scale=1): story_type = gr.Radio( choices=constants.STORY_TYPES, value=constants.DEFAULT_STORY_TYPE, interactive=True, label="Story Type", elem_id="story-type-buttons", ) # Tone with gr.Column(scale=1): tone = gr.Radio( choices=constants.TONE_TYPES, label="Story Tone", value=constants.DEFAULT_TONE_TYPE, interactive=True, elem_id="story-tone-buttons", ) return story_type, tone def create_reader_details(): """Create the reader details section""" with gr.Row(): # Kid Age with gr.Column(scale=1): kid_age = gr.Slider( minimum=constants.KID_AGE_MIN, maximum=constants.KID_AGE_MAX, value=constants.DEFAULT_KID_AGE, step=1, label="Kid Age", elem_id="age-slider", ) # Kid Language with gr.Column(scale=1): kid_language = gr.Textbox( label="Kid Language", value=constants.DEFAULT_LANGUAGE, elem_id="language-input", ) with gr.Row(): # Kid Interests with icon with gr.Column(): kid_interests = gr.Textbox( label="Kid Interests", placeholder="Robots, Space, Dinosaurs...", elem_id="interests-input", ) return kid_age, kid_language, kid_interests def create_story_details(): """Create the story details section""" with gr.Row(): # Subject with gr.Column(scale=1): subject = gr.Textbox( placeholder="MCP servers, Quantum Computing...", label="Subject (What is the story about?)", elem_id="subject-input", ) # Reading time with gr.Column(scale=1): reading_time = gr.Slider( minimum=constants.READING_TIME_MIN, maximum=constants.READING_TIME_MAX, value=constants.DEFAULT_READING_TIME, step=1, label="Reading Time (minutes)", elem_id="reading-time-slider", ) with gr.Row(): # PDF Upload with icon with gr.Column(scale=1): pdf_upload = gr.File( file_types=[".pdf"], label="PDF Upload (Optional)", elem_id="pdf-upload", ) # AI Model with icon (hidden behind a collapsible for simplicity) with gr.Column(scale=1): with gr.Accordion("Advanced: Choose AI Model", open=False): model_selector = gr.Dropdown( constants.MODEL_OPTIONS, label="AI Model", value=constants.DEFAULT_MODEL, elem_id="model-selector", ) return subject, reading_time, pdf_upload, model_selector def create_story_action_buttons(): """Create the action buttons for story generation""" with gr.Row(): generate_button = gr.Button( "โœจ Create My Magical Story! โœจ", variant="primary", ) clear_button = gr.Button( "๐Ÿงน Start Over", variant="secondary", ) return generate_button, clear_button def create_loading_container(): """Create the loading animation container""" with gr.Row(visible=False) as container: gr.HTML("""
๐Ÿ“š Creating your magical story... ๐Ÿ“š
""") return container def story_ready_header(): """Return the HTML for the story ready header""" return gr.HTML("""
Your Magical Story is Ready!
""") def create_story_output_container(): """Create the container for displaying the generated story""" story_title = gr.Textbox( label="Story Title", interactive=False, lines=1, elem_id="story-title", ) story_text = gr.Textbox( label="Generated Story", interactive=False, lines=15, elem_id="story-text", ) with gr.Row(): process_chapters_button = gr.Button( "๐ŸŽจ Create Illustrated Chapters! ๐ŸŽจ", variant="primary", interactive=False, elem_classes="chapters-button", ) return story_title, story_text, process_chapters_button def create_chapter_loading_container(): """Create the loading animation container for chapters""" with gr.Row(visible=False, elem_id="chapter-loading-container") as container: gr.HTML("""
...
""") return container def create_empty_chapters_placeholder(): """Create the placeholder for when no chapters are available""" return gr.HTML("""
Empty Book

Your Illustrated Story Awaits!

First, create your story and then click the "Create Illustrated Chapters!" button to see your story come to life with pictures!

""") def create_chapter_loading_placeholder(): return gr.HTML("""
โœจ๐Ÿ“šโœจ

Creating Your Magical Story Chapters...

Our wizard is crafting beautiful chapters and illustrations for your story...

""") def create_chapter_error_display(error_message): """Create an error display for chapter generation issues""" return gr.HTML(f"""

Oops! Something went wrong

{error_message}

""") def create_story_title_display(title): """Create a display for the story title""" return gr.HTML(f"""

{title}

""") def create_chapter_navigation(): """Create the chapter navigation display""" return gr.HTML("""

Your Adventure Chapters

Click on each chapter to reveal its magical contents!

""") def create_chapter_accordion(index, chapter): """Create an accordion for a story chapter""" with gr.Accordion( label=f"Chapter {index}: {chapter.get('title', 'Untitled')}", open=False, elem_classes="gr-accordion", ): with gr.Blocks(elem_classes="chapter-content-box"): # Chapter content with magical styling gr.HTML(f"""
{chapter.get("content", "")}
""") # Image prompt gr.HTML(f"""

Image Description:

{chapter.get("image_prompt", "")}

""") # Display image if available with nice styling image_b64 = chapter.get("image_b64") with gr.Row(equal_height=True): with gr.Column(scale=1): if image_b64: gr.HTML(f"""
Chapter Illustration
""") else: gr.HTML("""
๐Ÿ–Œ๏ธ

{status}

""") with gr.Column(scale=1): chapter_content_state = gr.State(value=chapter.get("content", "")) audio_statuss = gr.Markdown("", visible=False, elem_classes="text") read_aloud_btn = gr.Button( f"๐Ÿ”Š Read Chapter {index} Aloud", size="lg", variant="primary", elem_classes="audio-button", ) read_aloud_audio = gr.Audio( label="Generated Audio", interactive=False, autoplay=True, show_download_button=True, show_share_button=False, elem_classes="audio-output", waveform_options=gr.WaveformOptions( waveform_color="#ff9057", waveform_progress_color="#ff6a3b", skip_length=2, show_controls=True, ), ) return read_aloud_btn, read_aloud_audio, chapter_content_state, audio_statuss def create_story_melody_section(): """Create the section for generating a story melody""" gr.HTML("""
Musical headphone

Create a Magical Soundtrack for Your Story!

Click the button below to generate a special melody that matches the mood of your adventure!

""") with gr.Blocks(elem_classes="melody-box"): with gr.Row(): with gr.Column(scale=1, min_width=200): generate_melody_button = gr.Button( "๐ŸŽต Create Story Soundtrack ๐ŸŽต", variant="primary", elem_classes="melody-button", ) melody_status = gr.Markdown("", visible=False) with gr.Column(scale=2): melody_output = gr.Audio( label="Your Story's Magical Soundtrack", interactive=False, autoplay=True, show_download_button=True, show_share_button=False, waveform_options=gr.WaveformOptions( waveform_color="#9c5fff", waveform_progress_color="#6a2fff", skip_length=2, show_controls=True, ), ) return generate_melody_button, melody_status, melody_output # TODO split this further later def create_3d_model_viewer(story: str = "simple yellow duck"): """ Create a 3D model viewer component that displays a mesh from a base64 string. For now, this uses a placeholder HTML with a message and a download link for the mesh. In a real app, you would use a JS 3D viewer (e.g., Three.js) embedded in the HTML. """ gr.HTML("""

Create a Magical 3D Model from Your Story!

Click the button below to generate a 3D model from your story!

""") with gr.Blocks(elem_classes="melody-box"): with gr.Row(): with gr.Column(scale=1, min_width=200): generate_model_button = gr.Button( "Create 3D Model ๐ŸŽจ", variant="primary", elem_classes="melody-button", ) with gr.Column(scale=2): model_viewer = gr.Model3D( label="3D Model Viewer", clear_color=[0.0, 0.0, 0.0, 0.0] ) model_status = gr.Markdown("", visible=False) # Add status message and model display return ( generate_model_button, model_viewer, model_status, ) def create_readme_display(section_titles=None): """ Create a component that displays the project's README file. Optionally filter to show only specific sections by title. Args: section_titles (str or list, optional): If provided, only display these sections of the README. Can be a single string (e.g., "Getting Started") or a list of strings (e.g., ["Getting Started", "Features", "Installation"]). """ import re from pathlib import Path gr.set_static_paths(paths=[Path.cwd().absolute() / "/assets/images"]) # Handle single string for backward compatibility if isinstance(section_titles, str): section_titles = [section_titles] elif section_titles is None: section_titles = [] # Find the README file in the project root directory current_dir = Path(__file__).parent project_root = current_dir.parent readme_paths = [ project_root / "README.md", project_root / "Readme.md", project_root / "readme.md", ] readme_content = "" for path in readme_paths: if path.exists(): with open(path, "r", encoding="utf-8") as f: readme_content = f.read() break if not readme_content: readme_content = "README file not found in the project directory." # If specific sections are requested, extract them if section_titles and readme_content: # Pattern to match headers (# Header, ## Header, etc.) header_pattern = r"^(#+)\s+(.+)$" # Split the content by lines lines = readme_content.split("\n") all_filtered_content = [] # Process each requested section for section_title in section_titles: filtered_content = [] in_target_section = False current_level = 0 for line in lines: # Check if line is a header header_match = re.match(header_pattern, line, re.MULTILINE) if header_match: header_level = len(header_match.group(1)) # Number of # symbols header_text = header_match.group(2).strip() # If we found the target section if header_text.lower() == section_title.lower(): in_target_section = True current_level = header_level filtered_content.append(line) # Include the section header # If we're in the target section and find another header of same or higher level, exit section elif in_target_section and header_level <= current_level: in_target_section = False # Include subsection headers if we're in the target section elif in_target_section: filtered_content.append(line) # Include content if we're in the target section elif in_target_section: filtered_content.append(line) # Add this section's content to our combined content if filtered_content: all_filtered_content.extend(filtered_content) # Add a separator between sections unless it's the last section if section_title != section_titles[-1]: all_filtered_content.append("\n---\n") else: all_filtered_content.append( f"Section '{section_title}' not found in README.\n" ) # Update the content to only the filtered sections if all_filtered_content: readme_content = "\n".join(all_filtered_content) else: readme_content = "None of the requested sections were found in README." # Create a header similar to other components if not section_titles: section_display = "Full Documentation" elif len(section_titles) == 1: section_display = f"{section_titles[0]} Section" else: section_display = "Sections: " + ", ".join(section_titles) # Display the README content using Markdown with gr.Blocks(elem_classes="readme-box"): readme_display = gr.Markdown( value=readme_content, elem_classes="readme-content" ) return readme_display