Spaces:
Sleeping
Sleeping
| import os | |
| from groq import Groq | |
| import gradio as gr | |
| from gtts import gTTS | |
| import re | |
| groq_key = os.environ.get("GROQ_API_KEY") | |
| client = Groq(api_key=groq_key) | |
| def generate_story(age, theme, language): | |
| system_msg = {"role": "system", "content": "You write age-appropriate stories with complete endings and a moral."} | |
| age_i = int(age) | |
| length = "300 words" if age_i <= 6 else "600 words" if age_i <= 9 else "1000 words" | |
| user_msg = { | |
| "role": "user", | |
| "content": f"Write a complete story for a {age}-year-old child. Theme: {theme}. Language: {language}. Length about {length}. End with a clear moral of the story." | |
| } | |
| response = client.chat.completions.create( | |
| messages=[system_msg, user_msg], | |
| model="openai/gpt-oss-20b", | |
| max_tokens=2000, | |
| temperature=0.8 | |
| ) | |
| return response.choices[0].message.content.strip() | |
| def story_to_speech(story, language_code='en'): | |
| tts = gTTS(text=story, lang=language_code) | |
| filename = "/tmp/story.mp3" | |
| tts.save(filename) | |
| return filename | |
| def create_story_interface(age, theme, language, tts_option): | |
| story = generate_story(age, theme, language) | |
| story = re.sub(r'[*_#`~]', '', story) | |
| lines = story.split("\n", 1) | |
| title, rest_of_story = (lines[0], lines[1]) if len(lines) > 1 else (lines[0], "") | |
| if language.lower().startswith("u"): | |
| story_html = f'<div style="text-align:center; font-size:1.3em; direction:rtl; margin-bottom:5px;">{title}</div><div style="font-size:1.2em; direction:rtl; text-align:right;">{rest_of_story}</div>' | |
| lang_code = "ur" | |
| else: | |
| story_html = f'<div style="text-align:center; font-size:1.3em; direction:ltr; margin-bottom:5px;">{title}</div><div style="font-size:1.2em; direction:ltr; text-align:left;">{rest_of_story}</div>' | |
| lang_code = "en" | |
| audio_file = story_to_speech(story, lang_code) if tts_option else None | |
| return story_html, audio_file | |
| age_options = [str(i) for i in range(3, 13)] | |
| theme_options = ["Adventure","Animals","Fantasy","Educational","Friendship","Magic","Science","Mystery","Space","Nature","Kindness","Courage"] | |
| language_options = ["English", "Urdu"] | |
| # ----------------------------------------------- | |
| # GRADIO APP | |
| # ----------------------------------------------- | |
| with gr.Blocks() as iface: | |
| gr.HTML("""<style> | |
| @import url('https://fonts.googleapis.com/css2?family=Comic+Neue:wght@400;700&display=swap'); | |
| .gradio-container { font-family: 'Comic Neue', cursive !important; background: linear-gradient(135deg, #ffafbd, #ffc3a0) !important; padding-top: 10px !important; margin-top: -70px !important;} | |
| .main-header { text-align: center; font-weight: bold !important; font-size: 3.2em !important; margin-top: 40px !important; margin-bottom: 20px !important; text-shadow: 2px 2px 4px rgba(0,0,0,0.1); color: #12979B;} | |
| .story-container { background:#fff5ee; border-radius: 20px; padding: 25px; border: 5px solid #FFD166; box-shadow: 0 8px 25px rgba(0,0,0,0.1); min-height: 400px; margin-top: -20px !important;} | |
| .control-panel { background: #fff5ee; border-radius: 15px; padding: 20px; border: 3px dashed #4ECDC4; font-size: 1.2em !important; font-weight: 600; margin-top: -20px !important;} | |
| .generate-btn { background: linear-gradient(45deg, #FF6B6B, #FF9E7D) !important; border: none !important; border-radius: 50px !important; padding: 10px 22px !important; font-size: 1em !important; font-weight: bold !important; color: white !important; margin-top: 20px !important;} | |
| .generate-btn:hover { transform: scale(1.05); box-shadow: 0 5px 15px rgba(255, 107, 107, 0.4);} | |
| .dropdown, .checkbox { background: white !important; border-radius: 10px !important; border: 2px solid #96CEB4 !important;} | |
| .audio-player { border-radius: 15px !important; margin-top: 20px;} | |
| .subtitle { text-align: left; font-size: 1.5em !important; font-weight: 600; color: white; margin-top: -10px !important; margin-bottom: 20px; text-shadow: 1px 1px 2px rgba(0,0,0,0.1);} | |
| .footer { text-align: center; margin-top: 20px; color: #666; font-style: italic; font-size: 1.5em !important;} | |
| </style> | |
| """) | |
| gr.HTML("""<div class="main-header">π StoryTime AIπͺ</div>""") | |
| gr.HTML("""<div class="subtitle">π― Create amazing stories that spark imagination and teach valuable lessons!</div>""") | |
| with gr.Row(): | |
| with gr.Column(scale=1, min_width=300): | |
| with gr.Group(elem_classes="control-panel"): | |
| age_input = gr.Dropdown(age_options, label="πΆ Child's Age", value="5") | |
| theme_input = gr.Dropdown(theme_options, label="π Story Theme", value="Adventure") | |
| language_input = gr.Dropdown(language_options, label="π Language", value="English") | |
| tts_input = gr.Checkbox(label="π΅ Include Audio Story", value=True) | |
| generate_btn = gr.Button("β¨ Create Magical Story! β¨", elem_classes="generate-btn") | |
| with gr.Column(scale=2): | |
| with gr.Group(elem_classes="story-container"): | |
| story_output = gr.Markdown("Your story will appear here!", show_label=False) | |
| audio_output = gr.Audio(label="Audio Story", elem_classes="audio-player") | |
| gr.HTML("""<div class="footer">Made with β€οΈ for young readers everywhere! | Watch your stories come to life! β¨</div>""") | |
| generate_btn.click( | |
| create_story_interface, | |
| [age_input, theme_input, language_input, tts_input], | |
| [story_output, audio_output] | |
| ) | |
| iface.launch(ssr_mode=False) |