Spaces:
Sleeping
Sleeping
| """ | |
| Main application entry point file for the Magic Story Creator | |
| """ | |
| import gradio as gr | |
| import logging | |
| from dotenv import load_dotenv | |
| from pathlib import Path | |
| from ui.styles import main_css | |
| from ui.components import ( | |
| create_chapter_loading_placeholder, | |
| create_header, | |
| create_instructions_accordion, | |
| create_story_tab_header, | |
| create_step_heading, | |
| create_story_options, | |
| create_reader_details, | |
| create_story_details, | |
| create_story_action_buttons, | |
| create_loading_container, | |
| story_ready_header, | |
| create_story_output_container, | |
| create_chapter_loading_container, | |
| create_empty_chapters_placeholder, | |
| create_chapter_error_display, | |
| create_story_title_display, | |
| create_chapter_navigation, | |
| create_chapter_accordion, | |
| create_story_melody_section, | |
| create_3d_model_viewer, | |
| create_readme_display, | |
| ) | |
| # from ui.mcp_components import letter_counter_component | |
| from controllers.app_controller import ( | |
| generate_audio_with_status, | |
| generate_melody_from_story_with_status, | |
| generate_3d_model, | |
| ) | |
| from ui.events import setup_event_handlers | |
| # Configure logging | |
| logging.basicConfig( | |
| level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s" | |
| ) | |
| logger = logging.getLogger(__name__) | |
| # Load environment variables from .env file if present (local development) | |
| load_dotenv() | |
| # Set static paths for assets | |
| gr.set_static_paths(paths=[Path.cwd().absolute() / "assets/images"]) | |
| def create_app(): | |
| """Create the main Gradio app for Magic Story Creator""" | |
| with gr.Blocks( | |
| css=main_css, | |
| theme=gr.themes.Ocean(), | |
| title="Magic Tales", | |
| ) as demo: | |
| # Header | |
| create_header() | |
| # Instructions accordion | |
| create_instructions_accordion() | |
| # Create the main tabs | |
| tabs = gr.Tabs() | |
| with tabs: | |
| # Story Generator Tab | |
| with gr.Tab("Story Generator"): | |
| create_story_tab_header() | |
| # Story options | |
| with gr.Column(elem_classes="gr-form"): | |
| gr.HTML(create_step_heading(1, "Choose your adventure!")) | |
| story_type, tone = create_story_options() | |
| # Reader details | |
| with gr.Column(elem_classes="gr-form"): | |
| gr.HTML(create_step_heading(2, "Tell us about the reader!")) | |
| kid_age, kid_language, kid_interests = create_reader_details() | |
| # Story details | |
| with gr.Column(elem_classes="gr-form"): | |
| gr.HTML(create_step_heading(3, "Story details")) | |
| subject, reading_time, pdf_upload, model_selector = ( | |
| create_story_details() | |
| ) | |
| # Action buttons | |
| generate_button, clear_button = create_story_action_buttons() | |
| # Loading animation | |
| with gr.Row(visible=False): | |
| create_loading_container() | |
| # Story output container | |
| with gr.Blocks(elem_classes="gr-form", visible=False): | |
| story_ready_header() | |
| story_title, story_text, process_chapters_button = ( | |
| create_story_output_container() | |
| ) | |
| # Chapters & Image Prompts Tab | |
| with gr.Tab("Chapters & Image Prompts"): | |
| # State to store chapter data | |
| chapters_state = gr.State(value=None) | |
| # Chapter processing loading animation | |
| chapter_loading_container = create_chapter_loading_container() | |
| # Function to show the chapter loading container when processing starts | |
| def show_chapter_progress_container(): | |
| return gr.update(visible=True) | |
| # Connect process_chapters_button to show the loading container | |
| process_chapters_button.click( | |
| show_chapter_progress_container, | |
| inputs=[], | |
| outputs=[chapter_loading_container], | |
| ) | |
| def render_chapters(chapters_data): | |
| if chapters_data is None: | |
| return create_empty_chapters_placeholder() | |
| # Check if chapters_data is a string indicating an error or dict with error key | |
| if isinstance(chapters_data, str) and chapters_data.startswith( | |
| "Error:" | |
| ): | |
| return create_chapter_error_display(chapters_data) | |
| elif isinstance(chapters_data, dict) and "error" in chapters_data: | |
| return create_chapter_error_display(chapters_data["error"]) | |
| # Check if we're still processing | |
| if isinstance(chapters_data, dict) and chapters_data.get( | |
| "processing", False | |
| ): | |
| # If chapters exist but we're still processing, show them with loading indicators | |
| chapters = chapters_data.get("chapters", []) | |
| if chapters: | |
| # Display story title with magical styling | |
| create_story_title_display( | |
| chapters_data.get("title", "Story Chapters") | |
| ) | |
| # Chapter navigation | |
| create_chapter_navigation() | |
| # Display each chapter with appropriate loading indicators | |
| for i, chapter in enumerate(chapters, 1): | |
| status = chapter.get( | |
| "status", "Creating your magical illustration..." | |
| ) | |
| ( | |
| read_aloud_btn, | |
| read_aloud_audio, | |
| chapter_content_state, | |
| audio_statuss, | |
| ) = create_chapter_accordion(index=i, chapter=chapter) | |
| # Add audio generation functionality | |
| read_aloud_btn.click( | |
| generate_audio_with_status, | |
| inputs=[chapter_content_state], | |
| outputs=[read_aloud_audio, audio_statuss], | |
| ) | |
| return gr.update() | |
| else: | |
| # If no chapters yet, show a processing message | |
| return create_chapter_loading_placeholder() | |
| # Display story title with magical styling | |
| create_story_title_display( | |
| chapters_data.get("title", "Story Chapters") | |
| ) | |
| # Chapter navigation | |
| create_chapter_navigation() | |
| # Display each chapter with buttons in colorful cards | |
| for i, chapter in enumerate(chapters_data.get("chapters", []), 1): | |
| ( | |
| read_aloud_btn, | |
| read_aloud_audio, | |
| chapter_content_state, | |
| audio_statuss, | |
| ) = create_chapter_accordion(index=i, chapter=chapter) | |
| # Add audio generation functionality | |
| read_aloud_btn.click( | |
| generate_audio_with_status, | |
| inputs=[chapter_content_state], | |
| outputs=[read_aloud_audio, audio_statuss], | |
| ) | |
| # Story melody section | |
| generate_melody_button, melody_status, melody_output = ( | |
| create_story_melody_section() | |
| ) | |
| # Add melody generation from story functionality | |
| generate_melody_button.click( | |
| generate_melody_from_story_with_status, | |
| inputs=[story_text], | |
| outputs=[melody_output, melody_status], | |
| ) | |
| # 3D Model Viewer Tab (demo) | |
| generate_model_button, model_viewer, model_status = ( | |
| create_3d_model_viewer(story_text) | |
| ) | |
| # Connect the button to the generation function | |
| generate_model_button.click( | |
| generate_3d_model, | |
| inputs=[story_text], | |
| outputs=[model_viewer, model_status], | |
| ) | |
| with gr.Tab("README"): | |
| create_readme_display( | |
| ["π Magical Tales: Where Imagination Comes Alive! πβ¨"] | |
| ) | |
| # TODO DELETE THIS AS IT IRRELEVENT TO STORY GENERATION | |
| """ with gr.Tab("Character Counter"): | |
| letter_counter_component() """ | |
| # Set up event handlers | |
| setup_event_handlers( | |
| generate_button=generate_button, | |
| clear_button=clear_button, | |
| process_chapters_button=process_chapters_button, | |
| story_type=story_type, | |
| tone=tone, | |
| kid_age=kid_age, | |
| kid_language=kid_language, | |
| kid_interests=kid_interests, | |
| subject=subject, | |
| reading_time=reading_time, | |
| pdf_upload=pdf_upload, | |
| model_selector=model_selector, | |
| story_title=story_title, | |
| story_text=story_text, | |
| chapters_state=chapters_state, | |
| chapter_loading_container=chapter_loading_container, | |
| ) | |
| return demo | |
| # Create the main application | |
| demo = create_app() | |
| # Launch the Gradio app with enhanced settings | |
| if __name__ == "__main__": | |
| try: | |
| logger.info("Starting Magic Story Creator app") | |
| demo.launch(mcp_server=True) | |
| except Exception as e: | |
| logger.error(f"Failed to start app: {e}", exc_info=True) | |