Spaces:
Configuration error
Configuration error
| # app.py | |
| import streamlit as st | |
| from streamlit.components.v1 import html | |
| from story_engine.story_builder import build_story | |
| st.markdown(""" | |
| <meta name="viewport" content="width=device-width, initial-scale=1"> | |
| """, unsafe_allow_html=True) | |
| st.set_page_config(page_title="WikiTales", layout="centered") | |
| st.title("π WikiTales β Interactive Historical Storybooks") | |
| with st.container(): | |
| st.markdown("#### π Enter a historical figure or event:") | |
| topic = st.text_input( | |
| label="Search Topic", | |
| placeholder="e.g., French Revolution", | |
| key="search_box", | |
| label_visibility="collapsed" | |
| ) | |
| narrator = st.selectbox( | |
| "Choose Narrator Voice", | |
| options=["π Neutral Historian", "π° Wartime Journalist", "π©βπΎ Eyewitness", "π§ Fictional Guide", "π€ AI Assistant"], | |
| index=0 | |
| ) | |
| # ------------------------- | |
| # Carousel Renderer Function | |
| # ------------------------- | |
| def render_image_carousel(images): | |
| if not images: | |
| st.warning("No images found.") | |
| return | |
| # Build slides | |
| slides = "" | |
| for idx, img in enumerate(images): | |
| slides += f""" | |
| <div class="slide" id="slide-{idx}"> | |
| <img src="{img['url']}" alt="{img['title']}" /> | |
| <div class="caption">{img['title']}</div> | |
| </div>""" | |
| html_code = f""" | |
| <style> | |
| .carousel {{ position: relative; width: 100%; max-width: 700px; margin: auto; }} | |
| .slide {{ display: none; text-align: center; }} | |
| .slide img {{ max-width: 100%; max-height: 350px; border-radius: 8px; }} | |
| .caption {{ color: #fff; background: rgba(0,0,0,0.5); padding: 0.5em; position: absolute; bottom: 8px; width: 100%; }} | |
| .prev, .next {{ | |
| cursor: pointer; | |
| position: absolute; | |
| top: 50%; | |
| width: auto; | |
| margin-top: -22px; | |
| padding: 16px; | |
| color: white; | |
| font-weight: bold; | |
| font-size: 18px; | |
| border-radius: 0 3px 3px 0; | |
| user-select: none; | |
| }} | |
| .next {{ right: 0; border-radius: 3px 0 0 3px; }} | |
| </style> | |
| <div class="carousel"> | |
| {slides} | |
| <a class="prev" onclick="changeSlide(-1)">❮</a> | |
| <a class="next" onclick="changeSlide(1)">❯</a> | |
| </div> | |
| <script> | |
| let currentSlide = 0; | |
| const slides = document.getElementsByClassName('slide'); | |
| function showSlide(idx) {{ | |
| if (idx >= slides.length) currentSlide = 0; | |
| else if (idx < 0) currentSlide = slides.length - 1; | |
| else currentSlide = idx; | |
| for (let i = 0; i < slides.length; i++) {{ | |
| slides[i].style.display = 'none'; | |
| }} | |
| slides[currentSlide].style.display = 'block'; | |
| }} | |
| function changeSlide(n) {{ | |
| showSlide(currentSlide + n); | |
| }} | |
| showSlide(0); | |
| </script> | |
| """ | |
| html(html_code, height=420) | |
| # ------------------------- | |
| # Main Search + Display | |
| # ------------------------- | |
| if topic: | |
| with st.spinner(f"Generating story for '{topic}'..."): | |
| story_data = build_story(topic, narrator) | |
| story = story_data["story"] | |
| images = story_data["images"] | |
| wikibooks = story_data.get("wikibooks", []) # β added | |
| if story: | |
| render_image_carousel(images) | |
| st.markdown(f"#### ποΈ Narrated by: {narrator}") | |
| st.markdown("## π§ Generated Story") | |
| with st.container(): | |
| st.markdown(story, unsafe_allow_html=True) | |
| # β SIDEBAR: Wikibooks Deep Dive | |
| if wikibooks: | |
| with st.sidebar: | |
| st.markdown("## π Learn More on Wikibooks") | |
| for module in wikibooks: | |
| st.markdown(f"- [{module['title']}]({module['link']})") | |
| else: | |
| st.error("Sorry, we couldn't build a story. Try another topic.") | |