Spaces:
Running
Running
| import streamlit as st | |
| import sys | |
| import os | |
| sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) | |
| from src.story_gen import generate_story | |
| from pathlib import Path | |
| import threading | |
| import time | |
| import base64 | |
| # ------------------- WAV CLEANUP CONFIG ------------------- | |
| WAV_FOLDER = "." # Change to your folder name | |
| DELETE_AFTER_SECONDS = 300 | |
| def delete_wav_files(): | |
| """Delete .wav files older than 1 hour.""" | |
| if not os.path.exists(WAV_FOLDER): | |
| return | |
| current_time = time.time() | |
| for filename in os.listdir(WAV_FOLDER): | |
| if filename.endswith(".wav"): | |
| file_path = os.path.join(WAV_FOLDER, filename) | |
| try: | |
| file_age = current_time - os.path.getmtime(file_path) | |
| if file_age > DELETE_AFTER_SECONDS: | |
| os.remove(file_path) | |
| print(f"[CLEANER] Deleted (older than 1 hr): {file_path}") | |
| except Exception as e: | |
| print(f"[CLEANER] Error deleting {file_path}: {e}") | |
| def background_cleaner(): | |
| """Runs every 1 minute.""" | |
| while True: | |
| delete_wav_files() | |
| time.sleep(60) | |
| def load_app(): | |
| # Start background cleaner only once | |
| if "bg_started" not in st.session_state: | |
| threading.Thread(target=background_cleaner, daemon=True).start() | |
| st.session_state.bg_started = True | |
| print("[CLEANER] Background WAV cleaner started.") | |
| # # --- Sidebar Profile Section --- | |
| # profile_image_path = os.path.join(os.path.dirname(__file__), "profile.png") | |
| # # Read image safely | |
| # encoded_img = None | |
| # if os.path.exists(profile_image_path): | |
| # with open(profile_image_path, "rb") as img_file: | |
| # encoded_img = base64.b64encode(img_file.read()).decode() | |
| # # Sidebar HTML (centered layout) | |
| # sidebar_html = f""" | |
| # <div style="text-align:center; margin-top:20px;"> | |
| # <img src="data:image/png;base64,{encoded_img if encoded_img else ''}" | |
| # style="width:110px; height:110px; border-radius:50%; object-fit:cover; border:2px solid #ddd;"> | |
| # <div style="margin-top:10px; font-size:16px; font-weight:600; color:#333;"> | |
| # {"User:{}".format(st.session_state['user'])} | |
| # </div> | |
| # </div> | |
| # """ | |
| # st.sidebar.markdown(sidebar_html, unsafe_allow_html=True) | |
| # # Centered logout button | |
| # logout_style = """ | |
| # <style> | |
| # div.stButton > button:first-child { | |
| # display: block; | |
| # margin: 10px auto; | |
| # padding: 0.5rem 1rem; | |
| # border-radius: 8px; | |
| # font-size: 15px; | |
| # } | |
| # </style> | |
| # """ | |
| # st.sidebar.markdown(logout_style, unsafe_allow_html=True) | |
| st.sidebar.header("Options") | |
| page = st.sidebar.radio("Select Option", ["Story Using One Line Plot", "Story Using Custom Plot"],label_visibility="collapsed") | |
| if st.sidebar.button("Logout"): | |
| st.session_state.logged_in = False | |
| st.session_state.user = None | |
| st.session_state.show_audio = False | |
| st.session_state.bg_started = False | |
| st.rerun() | |
| if page == "Story Using One Line Plot": | |
| # ------------------- STREAMLIT APP ------------------- | |
| st.set_page_config( | |
| page_title="AI Story Generator", | |
| page_icon="π", | |
| layout="wide" # wide works best with no-scroll layouts | |
| ) | |
| # ------------------- CSS: Fit Window + No Scroll ------------------- | |
| css = """ | |
| <style> | |
| /* Remove scrolling */ | |
| html, body, [class*="css"] { | |
| height: 100%; | |
| overflow: hidden !important; | |
| } | |
| /* Reduce padding so content fits */ | |
| .block-container { | |
| padding-top: 1rem !important; | |
| padding-bottom: 1rem !important; | |
| max-width: 900px; /* keeps layout centered */ | |
| margin: auto; | |
| } | |
| /* Title spacing adjustment */ | |
| h1 { | |
| margin-top: 0 !important; | |
| } | |
| </style> | |
| """ | |
| st.markdown(css, unsafe_allow_html=True) | |
| # ------------------- UI ------------------- | |
| st.title("π KahiniLok") | |
| st.write("Enter a story plot and let AI turn it into a full story!") | |
| language = st.selectbox( | |
| "Select language for audio:", | |
| [ | |
| ("English", "en"), | |
| ("Hindi", "hi"), | |
| ("Tamil", "ta"), | |
| ("Telugu", "te"), | |
| ("Bengali", "bn"), | |
| ("Gujarati", "gu"), | |
| ("Kannada", "kn"), | |
| ("Malayalam", "ml") | |
| ], | |
| format_func=lambda x: x[0] | |
| ) | |
| plot = st.text_area("Enter your story plot:", height=150) | |
| display_story = st.checkbox("Display Story") | |
| generate = st.button("Generate Story") | |
| config={} | |
| config['lang']=language | |
| config['user']=st.session_state['user'] | |
| if generate: | |
| if not plot.strip(): | |
| st.warning("Please enter a story plot.") | |
| else: | |
| with st.spinner("Generating story... please wait β³"): | |
| response = generate_story(story_plot=plot, config=config) | |
| story = response.get("story") | |
| fileName = response.get("fileName") | |
| # Hold space for final audio output | |
| st.session_state["audio_file"] = fileName | |
| st.session_state["story_text"] = story | |
| st.session_state["show_audio"] = True | |
| if st.session_state.get("show_audio", False): | |
| st.markdown("---") | |
| st.subheader("π Generated Story Audio") | |
| f = Path(st.session_state["audio_file"]) | |
| audio_bytes = f.read_bytes() | |
| st.audio(audio_bytes, format="audio/wav") | |
| if display_story: | |
| st.markdown("---") | |
| st.subheader("π Full Story") | |
| st.write(st.session_state["story_text"]) | |
| if page == "Story Using Custom Plot": | |
| st.info("Story Using Custom Plot Feature development in progress") |